一.定义
Socket(套接字)是网络编程的核心,它允许不同主机或同一主机的不同进程之间进行通信,Socket API 提供了一套标准的接口,支持 TCP、UDP、IP 等协议
分为以下三个类型:
SOCK_STREAM:
用于tcp协议,可靠、面向连接、字节流,使用场景:HTTP、FTP、SSH
SOCK_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 通信了
最后,感谢你的支持!!!