一.定义
Socket(套接字)是网络编程的核心,它允许不同主机或同一主机的不同进程之间进行通信,Socket API 提供了一套标准的接口,支持 TCP、UDP、IP 等协议
分为以下三个类型:
SOCK_STREAM:
用于tcp协议,可靠、面向连接、字节流,使用场景:HTTP、FTP、SSHSOCK_DGRAM:
用于udp协议,不可靠、无连接、数据报,使用场景:DNS、视频流、游戏SOCK_RAW:
用于IP/ICMP 原始套接字(直接访问网络层),使用场景:网络嗅探、自定义协议
地址结构:
IPV4: struct sockaddr_in
struct sockaddr_in {sa_family_t sin_family; // 地址族(AF_INET)in_port_t sin_port;// 端口号(16位,需用 htons() 转换)struct in_addr sin_addr; // IP地址(32位,需用 inet_addr() 或 htonl())char sin_zero[8]; //填充(保持与 sockaddr 大小一致)
};
IPV6:struct sockaddr_in6
通用结构:struct sockaddr
struct sockaddr {sa_family_t sa_family; //地址族(AF_INET, AF_INET6, AF_UNIX)char sa_data[14]; //实际地址数据
};
二.API接口(核心)
socket():
作用:创建套接字
//头文件:
#include <sys/socket.h>int socket(int domain,int type,int protocol);domain --- 协议族(AF_INET、AF_INET6、AF_UNIX)
type --- 套接字类型(SOCK_STREAM、SOCK_DGRAM)
protocol --- 控制,通常填 0(自动选择,如 IPPROTO_TCP)返回值:
-1 --- 创建失败
其他 --- 创建成功,并返回socketfd(套接字描述符)
举例:
#include <iostream>
#include <sys/socket.h>int socketfd = socket(AF_INET,SOCK_STREAM,0);
//检查:
if(socketfd == -1){std::cerr<<"socket creation failed"<<std::endl;exit(EXIT_FAILURE);
}
//创建成功
bind():
绑定IP和端口
//头文件:
#include <sys/socket.h>int bind(int socketfd,const struct sockaddr* addr,socklen_t addrlen);//参数:
socketfd --- 套接字描述符
addr --- 指向 sockaddr_in 或 sockaddr_in6 的指针(需强制转换)
addrlen --- 地址结构的大小(sizeof(struct sockaddr_in))//返回值:
-1 --- 绑定失败
其他(0)--- 绑定成功
举例:
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8080);
server_addr.sin_addr.s_addr = INADDR_ANY;if(bind(sockfd,(struct sockaddr*)&server_addr,sizeof(server_addr)
{ perror("bind failed");exit(EXIT_FAILURE);
}
listen():
监听连接(TCP)
#include <sys/socket.h>int listen(int sockfd,int backlog);//参数:
sockfd --- 套接字描述符
backlog --- 等待连接队列的最大长度//返回值:
-1 --- 失败
其他(0)--- 成功
举例:
if (listen(sockfd, 5) == -1) {perror("listen failed");exit(EXIT_FAILURE);
}
accept():
接收连接
#include <sys/socket.h>int accept(int sockfd,struct socketaddr* addr,socklen_t* addrlen);//参数:
sockfd --- 套接字描述符
addr --- 用于存储客户端地址
addrlen --- 地址结构大小(需先初始化)//返回值:
-1 --- 连接失败
其他 --- 连接成功,返回的是新的套接字描述符
举例:
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
int connet_fd = accpet(sockfd,(struct socketaddr*)&client_addr,&client_len);
if(connet_fd == -1)
{perror("accept failed");exit(EXIT_FAILURE);
}
//连接成功
connect():
用户向服务器发起连接
#include <sys/socket.h>int connect(int sockfd,const struct sockaddr *addr, socklen_t addrlen);//参数:
sockfd --- 套接字描述符
addr --- 服务器地址
addrlen --- 地址结构大小//返回值:
-1 --- 连接失败
其他(0)--- 连接成功
举例:
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htos(8080);
//解析IP:
inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr); //连接并判断:
if(connect(sockfd,(struct sockaddr*)&server_addr,sizeof(server_addr)) == -1)
{perror("connect failed");exit(EXIT_FAILURE);
}
//连接成功
send/recv:
TCP数据收发
#include <sys/socket.h>//发送数据:
ssize_t send(int sockfd,const void *buf, size_t len, int flags);//接收数据:
ssize_t recv(int sockfd,void *buf, size_t len, int flags);//buf内容要填充的,不能用const//参数:
sockfd --- 已连接的套接字
buf --- 数据缓冲区
len --- 数据长度
flags --- 可选标志(如 MSG_WAITALL 阻塞直到收满)//返回值:
-1 --- 失败
其他 --- 成功 并返回发送/接收的字节数
举例:
char buffer[1024];//缓冲区
ssize_t bytes_received = recv(connect_fd,buffer,sizeof(buffer),0);
if(bytes_received == -1)
{perror("recv failed");
}
else
{buffer[bytes_received] = '\0'; // 确保字符串终止printf("Received: %s\n", buffer);
}
sendto/recvfrom:
UDP数据收发
#include <sys/socket.h>//发送数据:
ssize_t sendto(int sockfd,const void* buf,size_t len,int flags,const struct sockaddr* dest_addr,socklen_t addrlen);//接收数据:
ssize_t recvfrom(int sockfd,void* buf,size_t len,int flags,struct sockaddr* src_addr,socklen_t* socklen);//参数:
很多之前我们已经讲过了,讲下几个没讲的
dest_addr / src_addr --- 目标/源地址//返回值:
-1 --- 发送、接收失败
其他 --- 返回发送/接收的字节数
举例:
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
char buffer[1024];
ssize_t bytes_recvfrom = recvfrom(sockfd,buffer,sizeof(buffer),0,(struct sockaddr*)&client_addr,&client_len);
if(bytes_recvfrom == -1)
{perror("recvfrom failed");
}
//接收成功
close()
关闭套接字
#include <unistd.h>//Linux系统下:
int close(int sockfd);//补充:Windows系统下
#incluide <winsock2.h>
int closesocket(SOCKET sockfd);//也是关闭连接,但是可以自己选择
int shutdown(int sockfd, int how);//参数:
how --- 1.SHUT_RD:关闭读取 2.SHUT_WR:关闭写入 3.SHUT_RDWR:完全关闭
掌握这些 API 后,你可以实现基本的 TCP 服务器/客户端 和 UDP 通信了
最后,感谢你的支持!!!