TCP UDP的socket套接字编程学习
TCP与UDP均工作于传输层,TCP是有连接的,安全的,注重数据完整性;这些特点也导致了两者的使用途径的不同,TCP用于数据比较重要,但是不注重时效性的数据,而UDP则用于数据丢包后影响较小的地方。sockfd为套接字描述符,参数一int domain:AF_INET为协议族,可选AF_INET(IPv4),AF_INET6(IPv6);(struct sockaddr*)&addr:本地IP地址
一 TCP与UDP的异同
TCP与UDP均工作于传输层,TCP是有连接的,安全的,注重数据完整性;UDP是无连接的,不安全的,注重实时性。这里的有连接和无连接的区别并不在于是否连接网线,而是在于在传输数据时是否需要建立连接。这里的安全并不是指的会不会被攻击或者其他,而是指数据完整性。TCP注重数据完整性,当对端没有接收到数据时,本端会再次发送。而UDP则注重于数据的实时性,发生丢包时并不会重发。这些特点也导致了两者的使用途径的不同,TCP用于数据比较重要,但是不注重时效性的数据,而UDP则用于数据丢包后影响较小的地方。
二 TCP,UDP通信流程
此为Linux系统下的通信流程,从上图可以看出TCP在通信时比UDP多了listen(),accept(),connect()函数,这就是第一节所对比的有连接和无连接,UDP在创建套接字后直接就可以发送数据,而TCP则需要先建立连接。TCP的三次握手也是发生在这里。注意:两者的发送和接收函数也并不同,并且使用套接字后必须关闭。
Windows与上图基本类似,但是多了几个函数,首先就是在使用套接字之前需要使用WSAStartup()初始化WinSock库,并且需要链接ws2_32.lib,使用完后不仅需要关闭套接字还需要清理环境WSACleanup()。
三 socket套接字常见API函数及使用方法
通用函数(适用于Windows和Linux)
socket()
: 创建套接字。int sockfd = socket(AF_INET, SOCK_STREAM, 0);
sockfd为套接字描述符,参数一int domain:AF_INET为协议族,可选AF_INET(IPv4),AF_INET6(IPv6); 参数二int type:SOCK_STREAM为TCP协议类型,可选SOCK_DGRAM为UDP协议类型; 参数三int protocol:默认0; 错误返回-1;
htons()
: 绑定端口,将主机字节序转换为网络字节序(用于端口号)。-
struct sockaddr_in addr; addr.sin_family = AF_INET; // IPv4 地址族 addr.sin_addr.s_addr = INADDR_ANY; // 绑定到所有可用IP addr.sin_port = htons(8080); // 将端口号 8080 转换为网络字节序
将端口8080转换为网络字节序,注:struct sockaddr_in addr 为IP地址信息结构体。
struct sockaddr_in addr; // 初始化结构体(所有成员设为 0) memset(&addr, 0, sizeof(addr)); // 设置地址族为 IPv4 addr.sin_family = AF_INET; // 设置端口号(8080,转换为网络字节序) addr.sin_port = htons(8080); // 关键:使用 inet_pton 转换 IP 地址到结构体的 sin_addr 成员 // 将 "127.0.0.1" 转换为网络字节序,并存储到 addr.sin_addr 中 if (inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr) <= 0) { std::cerr << "IP 地址转换失败" << std::endl;
ntohs()
: 解析端口将网络字节序转换为主机字节序(用于获取对方端口号)。uint16_t net_port = htons(8080); // 模拟网络传输的端口号 // 转换为本地主机字节序 uint16_t host_port = ntohs(net_port);
inet_pton()
: 配置目标IP,本地IP将IP地址从文本格式转换为二进制格式(网络字节序)。inet_pton(AF_INET, "127.0.0.1",&addr.sin_addr)
AF_INET:IPv4协议族;“127.0.0.1”:具体IP地址;&addr.sin_addr:需要存放IP地址的指针。成功返回 1,无效地址返回 0,错误返回 -1。
inet_ntop()
: 打印对方IP,将IP地址从二进制格式(网络字节序)转换为文本格式。inet_ntop(AF_INET, &addr.sin_addr, ip_str, INET_ADDRSTRLEN)
&addr.sin_addr:存放二进制IP 的指针;ip_str:将要存放字符串地址的指针;INET_ADDRSTRLEN :字符穿IP指针指向的缓冲区大小;
bind()
: 服务器绑定本地IP和端口,以方便监听连接请求。返回值为0,-1(失败)
bind(sockfd, (struct sockaddr*)&addr, sizeof(addr))
sockfd:套节字描述符;(struct sockaddr*)&addr:本地IP地址结构体指针(转换为struct socket*类型)sizeof(addr):IP地址结构体的大小;
connect()
: 客户端用于发起连接到服务器。
connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr))
sockfd:套接字 描述符; (struct sockaddr*)&serv_addr:服务器地址结构体;sizeof(serv_addr):服务器地址结构体的大小;
listen()
: 用于监听bind()
绑定的IP和端口
listen(sockfd, backlog)
sockfd:已绑定地址的套接字描述符(通过 socket()
创建并经 bind()
绑定)backlog
:监听队列的最大长度,用于限制等待接受的连接请求数量
accept()
: 接收客户端连接请求,并创建新的套接字用于数据传输。
int client_sock = accept(listen_sock, (struct sockaddr*)&client_addr, &client_addr_len);
sockfd:处于监听状态的套接字描述符;(struct sockaddr*)&client_addr:存储客户端的IP地址信息结构体;&client_len:该信息结构体的大小;
recv()
: TCP接收数据。
recv(sockfd, buffer, sizeof(buffer) - 1, 0)
sockfd:本地已连接的套接字描述符(客户端的 sockfd
或服务器通过 accept()
获得的 client_sock
);buffer:接收缓冲区指针;sizeof(buffer)-1:缓冲区的最大长度;0:默认0;
send()
: TCP发送数据。
// 成功返回发送的字节数,失败返回 -1(Windows 为 SOCKET_ERROR)
send(sockfd, msg, msg_len, 0)
sockfd:本地已连接的套接字描述符(客户端的 sockfd
或服务器通过 accept()
获得的 client_sock
);msg:待发送缓冲区指针;msg_len:缓冲区的最大长度;0:默认0;
recvfrom()
: UDP接收数据。
recvfrom(sockfd, buffer, sizeof(buffer)-1, 0,(struct sockaddr*)&sender_addr, &sender_len);
sockfd:UDP套接字;buffer:接收数据缓冲区;sizeof(buffer) -1:缓冲区最大长度;0:默认0; (struct sockaddr*)&sender_addr输出参数,用于存储发送方的地址信息(struct sockaddr*
类型) ;&sender_len:输入时为 src_addr
大小,输出时为实际地址长度。
sendto()
: UDP发送数据。
sendto (sockfd, send_msg, strlen (send_msg), 0, (struct sockaddr*)&server_addr, sizeof (server_addr)
sockfd:UDP套接字;send_msg:待发送数据缓冲区;strlen(send_msg):缓冲区最大长度;0:默认0;(struct sockaddr*)&sender_addr目标地址(struct sockaddr*
类型) ;&sender_len:输入时为 src_addr
大小,输出时为实际地址长度。
Windows特定函数
WSAStartup()
: 使用socket套接字前,需初始化WinSock库。WSACleanup()
: 使用socket套接字后,需终止对WinSock库的使用。
closesocket()
: 关闭套接字。WSAGetLastError()
: 获取错误码。
Linux特定函数
close()
: 关闭套接字。errno
: 获取错误码(全局变量)。
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
WSACleanup();
closesocket(sockfd);
close(sockfd)
更多推荐
所有评论(0)