Skip to content

Socket套接字

Socket 是一个编程接口(网络编程接口),是一种特殊的文件描述符(write/read)。Socket 并不仅限于 TCP/IP。
Socket 独立于具体协议的编程接口,这个接口位于 TCP/IP 四层模型的应用层与传输层之间。

Socket的类型

  • 流式套接字SOCK_STREAM):
    • 面向字节流,针对于传输层协议为 TCP 协议的网络应用。
  • 数据报套接字SOCK_DGRAM):
    • 面向数据报,针对于传输层协议为 UDP 协议的网络应用。
  • 原始套接字SOCK_RAW):
    • 直接跳过传输层。

基于 TCP 的套接字编程流程

任何网络应用都会有通信双方:

  • Send 发送端
  • Recv 接收端

TCP 网络应用(C/S 模型)(长连接):

  • Client 客户端(TCP)
  • Server 服务端(TCP)

任何的网络应用

  • 传输层的协议(TCP/UDP)+ 端口 + IP 地址
  • 网络地址:任意一方都需要有一个网络地址(IP+端口)

TCP 网络应用执行过程

  1. 建立连接:三次握手
  2. 发送/接收数据
    • 发送数据:write/send/sendto
    • 接收数据:read/recv/recvfrom
  3. 关闭连接:四次挥手

TCP-Server 服务端编程流程

1. 建立套接字:socket()

c
#include <sys/types.h>  
#include <sys/socket.h>  

int socket(int domain, int type, int protocol);
  • 描述:申请指定类型和协议的套接字。
  • 参数
    • domain:协议簇(如 AF_INET IPv4, AF_INET6 IPv6)。
    • type:套接字类型(如 SOCK_STREAM TCP, SOCK_DGRAM UDP)。
    • protocol:具体协议(通常为 0)。
  • 返回值:成功返回套接字描述符,失败返回 -1。

2. 绑定网络地址:bind()

c
#include <sys/types.h>  
#include <sys/socket.h>  

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • 描述:将套接字绑定到网络地址。
  • 参数
    • sockfd:套接字描述符。
    • addr:网络地址结构体(如 struct sockaddr_in)。
    • addrlen:地址结构体长度。
  • 地址结构示例
    c
    struct sockaddr_in sock_info;  
    sock_info.sin_family = AF_INET;          // IPv4  
    sock_info.sin_port = htons(6666);        // 端口  
    sock_info.sin_addr.s_addr = inet_addr("192.168.31.1"); // IP
  • 返回值:成功返回 0,失败返回 -1。

3. 监听连接:listen()

c
#include <sys/types.h>  
#include <sys/socket.h>  

int listen(int sockfd, int backlog);
  • 描述:设置套接字进入监听模式。
  • 参数
    • sockfd:套接字描述符。
    • backlog:最大等待连接队列长度。
  • 返回值:成功返回 0,失败返回 -1。

4. 接受客户端连接:accept()

c
#include <sys/types.h>  
#include <sys/socket.h>  

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
  • 描述:等待客户端连接(完成三次握手)。
  • 参数
    • sockfd:监听套接字描述符。
    • addr:存储客户端地址的结构体。
    • addrlen:地址结构体长度指针。
  • 返回值:成功返回通信套接字描述符,失败返回 -1。

5. 数据传输:send()recv()

c
#include <sys/types.h>  
#include <sys/socket.h>  

ssize_t send(int sockfd, const void *buf, size_t len, int flags);
  • 描述:向套接字写入数据。
  • 参数
    • sockfd:通信套接字描述符。
    • buf:待发送数据指针。
    • len:数据长度。
    • flags:标志位(通常为 0)。
  • 返回值:成功返回实际发送字节数,失败返回 -1。
c
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
  • 描述:从套接字读取数据。
  • 参数:同 send()
  • 返回值:成功返回实际接收字节数,失败返回 -1。

6. 关闭套接字:shutdown()close()

c
#include <sys/socket.h>  

int shutdown(int sockfd, int how);
  • 描述:关闭套接字连接(触发四次挥手)。
  • 参数
    • sockfd:套接字描述符。
    • how:关闭方式(SHUT_RD, SHUT_WR, SHUT_RDWR)。

TCP-Client 客户端编程流程

1. 建立套接字:socket()

同服务端。

2. 绑定地址(可选)

通常不绑定,由系统分配。

3. 发起连接请求:connect()

c
#include <sys/types.h>  
#include <sys/socket.h>  

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • 描述:向目标地址发起连接请求。
  • 参数
    • sockfd:套接字描述符。
    • addr:目标服务器地址结构体。
    • addrlen:地址结构体长度。
  • 返回值:成功返回 0,失败返回 -1。

4. 数据传输:send()recv()

同服务端。

5. 关闭套接字:close()

同服务端。


基于 UDP 的套接字编程流程

UDP 是面向无连接的传输层协议:

  • 网络环境较好时效率高,较差时可能丢包。
  • 适用于实时应用(需在应用层增加可靠性控制)。

UDP Recver(接收端)

  1. 创建套接字socket()(类型为 SOCK_DGRAM)。
  2. 绑定地址bind()(指定接收端口)。
  3. 接收数据recvfrom()
    c
    ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,  
                     struct sockaddr *src_addr, socklen_t *addrlen);
    • 参数
      • src_addr:存储发送方地址的结构体(可为 NULL)。
      • addrlen:地址结构体长度指针。
  4. 关闭套接字close()

UDP Sender(发送端)

  1. 创建套接字socket()(类型为 SOCK_DGRAM)。
  2. 发送数据sendto()
    c
    ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,  
                   const struct sockaddr *dest_addr, socklen_t addrlen);
    • 参数
      • dest_addr:目标地址结构体。
      • addrlen:地址结构体长度。
  3. 关闭套接字close()

网络通信协议

协议是通信双方约定的规则:

示例 1:字符分隔

  • 用特殊字符标记开始/结束(如 STX/ETX)。
  • 数据为明文,长度不限。

示例 2:结构化数据包

c
struct package {  
    int number;         // 数据包序号  
    enum { CMD, MSG, IMG } type; // 数据类型  
    int size;           // 数据实际大小  
    char buffer[1024];  // 数据内容  
};

作业

  1. TCP 封装:将 TCP 操作封装成一个类。
  2. UDP 文件传输:实现 UDP 发送端和接收端,支持发送文件。

知识如风,常伴吾身