套接字通信socket
一、套接字的概念
套接字是一种用于网络通信的编程接口,它提供了一种在不同主机上的进程之间进行通信的机制。套接字允许应用程序在网络上发送和接收数据,就像文件操作允许程序在本地存储上读写数据一样。它是网络通信的端点,每个套接字都由一个 IP 地址和一个端口号组成,通过这两个元素可以唯一地标识网络中的一个通信进程。
编辑
二、套接字的类型
- 流式套接字(Stream Sockets):
- 基于 TCP(Transmission Control Protocol)协议,提供面向连接、可靠的字节流服务。
- 数据传输是顺序的、无差错的、无重复的,并且保证数据的完整性和可靠性。
- 适用于需要可靠传输的应用,如文件传输、HTTP、SMTP、FTP 等。
- 在 C++ 中,使用
SOCK_STREAM
常量表示。
- 数据报套接字(Datagram Sockets):
- 基于 UDP(User Datagram Protocol)协议,提供无连接、不可靠的数据报服务。
- 每个数据报是独立的消息,不保证顺序,也不保证接收方一定能收到数据报。
- 适合对传输速度要求较高但对数据完整性要求相对较低的应用,如音频、视频流、DNS 查询等。
- 在 C++ 中,使用
SOCK_DGRAM
常量表示。
三、套接字的地址结构
在 C++ 中,使用 sockaddr_in
结构来表示 IPv4 地址,主要成员包括:
1 | struct sockaddr_in { |
in_addr
结构包含一个 s_addr
成员,存储 32 位的 IPv4 地址,可以使用 inet_addr
函数将点分十进制的 IP 地址转换为网络字节序的 32 位整数。
四、套接字编程的基本步骤
服务器端:
1.创建套接字:
1 | int serverSocket = socket(AF_INET, SOCK_STREAM, 0); |
AF_INET
:使用 IPv4 地址族。SOCK_STREAM
:创建一个流式套接字(TCP)。0
:使用默认协议。- 函数返回一个套接字描述符,若失败则返回 -1。
2.绑定地址和端口:
1 | struct sockaddr_in serverAddress; |
- 将服务器地址和端口绑定到创建的套接字上。
htons
函数将端口号从主机字节序转换为网络字节序。INADDR_ANY
表示接受来自任何网络接口的连接。bind
函数将套接字与地址结构绑定,失败返回 -1。
3.监听连接请求:
1 | listen(serverSocket, 5); |
- 开始监听客户端的连接请求。
5
表示等待队列的最大长度,即最多允许 5 个未处理的连接请求。- 失败返回 -1。
4.接受连接请求:
1 | int clientSocket = accept(serverSocket, (struct sockaddr*)&clientAddress, &clientAddressLength); |
- 阻塞函数,等待客户端的连接请求,一旦有请求就接受并创建一个新的套接字
clientSocket
用于与客户端通信。 clientAddress
是一个sockaddr_in
结构,存储客户端的地址信息。- 失败返回 -1。
5.数据传输:
1 | char buffer[1024]; |
recv
函数从客户端接收数据。send
函数向客户端发送数据。- 可以使用
sendall
函数确保完整发送数据,处理可能的部分发送情况。
6.关闭套接字:
1 | close(clientSocket); |
- 关闭客户端和服务器的套接字,释放资源。
客户端:
1.创建套接字:
1 | int clientSocket = socket(AF_INET, SOCK_STREAM, 0); |
- 与服务器创建套接字的过程相同。
2.指定服务器地址和端口:
1 | struct sockaddr_in serverAddress; |
- 设置服务器的 IP 地址和端口号。
inet_addr
函数将点分十进制的 IP 地址转换为网络字节序。
3.连接服务器:
1 | connect(clientSocket, (struct sockaddr*)&serverAddress, sizeof(serverAddress)); |
- 向服务器发起连接请求,失败返回 -1。
4.数据传输:
1 | send(clientSocket, message, strlen(message), 0); |
- 发送和接收数据。
5.关闭套接字:
1 | close(clientSocket); |
五、重要函数详解
1. socket 函数:
1 | int socket(int domain, int type, int protocol); |
domain
:地址族,如AF_INET
(IPv4)或AF_INET6
(IPv6)。type
:套接字类型,如SOCK_STREAM
(TCP)或SOCK_DGRAM
(UDP)。protocol
:协议,通常为 0 表示使用默认协议。
2. bind 函数:
1 | int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); |
sockfd
:套接字描述符。addr
:指向包含地址和端口信息的sockaddr
结构的指针。addrlen
:addr
结构的长度。
3. listen 函数:
1 | int listen(int sockfd, int backlog); |
sockfd
:套接字描述符。backlog
:等待队列的最大长度。
4. accept 函数:
1 | int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); |
sockfd
:监听套接字的描述符。addr
:存储客户端地址信息的sockaddr
结构指针。addrlen
:addr
结构的长度指针,存储客户端地址长度。
5. connect 函数:
1 | int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); |
sockfd
:客户端套接字描述符。addr
:服务器的地址信息。addrlen
:地址信息的长度。
6. send 和 recv 函数:
1 | ssize_t send(int sockfd, const void *buf, size_t len, int flags); |
sockfd
:套接字描述符。buf
:发送或接收数据的缓冲区。len
:缓冲区的长度。flags
:通常为 0,可设置为MSG_OOB
等特殊标志
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 lte'Blog!