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 网络应用执行过程
- 建立连接:三次握手
- 发送/接收数据:
- 发送数据:
write/send/sendto - 接收数据:
read/recv/recvfrom
- 发送数据:
- 关闭连接:四次挥手
TCP-Server 服务端编程流程
1. 建立套接字:socket()
c
#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain, int type, int protocol);- 描述:申请指定类型和协议的套接字。
- 参数:
domain:协议簇(如AF_INETIPv4,AF_INET6IPv6)。type:套接字类型(如SOCK_STREAMTCP,SOCK_DGRAMUDP)。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(接收端)
- 创建套接字:
socket()(类型为SOCK_DGRAM)。 - 绑定地址:
bind()(指定接收端口)。 - 接收数据:
recvfrom()cssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);- 参数:
src_addr:存储发送方地址的结构体(可为NULL)。addrlen:地址结构体长度指针。
- 参数:
- 关闭套接字:
close()。
UDP Sender(发送端)
- 创建套接字:
socket()(类型为SOCK_DGRAM)。 - 发送数据:
sendto()cssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);- 参数:
dest_addr:目标地址结构体。addrlen:地址结构体长度。
- 参数:
- 关闭套接字:
close()。
网络通信协议
协议是通信双方约定的规则:
示例 1:字符分隔
- 用特殊字符标记开始/结束(如
STX/ETX)。 - 数据为明文,长度不限。
示例 2:结构化数据包
c
struct package {
int number; // 数据包序号
enum { CMD, MSG, IMG } type; // 数据类型
int size; // 数据实际大小
char buffer[1024]; // 数据内容
};作业
- TCP 封装:将 TCP 操作封装成一个类。
- UDP 文件传输:实现 UDP 发送端和接收端,支持发送文件。
