c++ Socket学习——使用listen(),accept(),write(),read()函数

7 篇文章 3 订阅
5 篇文章 1 订阅

对于服务器端程序,使用 bind() 绑定套接字后,还需要使用 listen() 函数让套接字进入被动监听状态,再调用 accept() 函数,就可以随时响应客户端的请求了。

listen() 函数

通过 listen() 函数可以让套接字进入被动监听状态,它的原型为:

int listen(int sock, int backlog); //Linux
int listen(SOCKET sock, int backlog); //Windows

sock 为需要进入监听状态的套接字,backlog 为请求队列的最大长度。

所谓被动监听,是指当没有客户端请求时,套接字处于“睡眠”状态,只有当接收到客户端请求时,套接字才会被“唤醒”来响应请求。所以,执行accept的是被动套接字,执行connect的是主动套接字。

请求队列
当套接字正在处理客户端请求时,如果有新的请求进来,套接字是没法处理的,只能把它放进缓冲区,待当前请求处理完毕后,再从缓冲区中读取出来处理。如果不断有新的请求进来,它们就按照先后顺序在缓冲区中排队,直到缓冲区满。这个缓冲区,就称为请求队列(Request Queue)。

缓冲区的长度(能存放多少个客户端请求)可以通过 listen() 函数的 backlog 参数指定,但究竟为多少并没有什么标准,可以根据你的需求来定,并发量小的话可以是10或者20。

如果将 backlog 的值设置为 SOMAXCONN,就由系统来决定请求队列长度,这个值一般比较大,可能是几百,或者更多。

当请求队列满时,就不再接收新的请求,对于 Linux,客户端会收到 ECONNREFUSED 错误,对于 Windows,客户端会收到 WSAECONNREFUSED 错误。

注意:listen() 只是让套接字处于监听状态,并没有接收请求。接收请求需要使用 accept() 函数。

accept() 函数

当套接字处于监听状态时,可以通过 accept() 函数来接收客户端请求。它的原型为:

int accept(int sock, struct sockaddr *addr, socklen_t *addrlen); //Linux
SOCKET accept(SOCKET sock, struct sockaddr *addr, int *addrlen); //Windows

它的参数与 listen() 和 connect() 是相同的:sock 为服务器端套接字,addr 为 sockaddr_in 结构体变量,addrlen 为参数 addr 的长度,可由 sizeof() 求得。

accept() 返回一个新的套接字来和客户端通信,addr 保存了客户端的IP地址和端口号,而 sock 是服务器端的套接字,大家注意区分。后面和客户端通信时,要使用这个新生成的套接字,而不是原来服务器端的套接字。

最后需要说明的是:listen() 只是让套接字进入监听状态,并没有真正接收客户端请求,listen() 后面的代码会继续执行,直到遇到 accept()。accept() 会阻塞程序执行(后面代码不能被执行),直到有新的请求到来。

Linux 不区分套接字文件和普通文件,使用 write() 可以向套接字中写入数据,使用 read() 可以从套接字中读取数据。

Linux下数据的接收和发送

前面我们说过,两台计算机之间的通信相当于两个套接字之间的通信,在服务器端用 write() 向套接字写入数据,客户端就能收到,然后再使用 read() 从套接字中读取出来,就完成了一次通信。

write() 的原型为:

ssize_t write(int fd, const void *buf, size_t nbytes);

fd 为要写入的文件的描述符,buf 为要写入的数据的缓冲区地址,nbytes 为要写入的数据的字节数。

size_t 是通过 typedef 声明的 unsigned int 类型;
ssize_t 在 "size_t" 前面加了一个"s",代表 signed,
即 ssize_t 是通过 typedef 声明的 signed int 类型。

write() 函数会将缓冲区 buf 中的 nbytes 个字节写入文件 fd,成功则返回写入的字节数,失败则返回 -1。

read() 的原型为:

ssize_t read(int fd, void *buf, size_t nbytes);

fd 为要读取的文件的描述符,buf 为要接收数据的缓冲区地址,nbytes 为要读取的数据的字节数。

read() 函数会从 fd 文件中读取 nbytes 个字节并保存到缓冲区 buf,成功则返回读取到的字节数(但遇到文件结尾则返回0),失败则返回 -1。

Windows下数据的接收和发送

Windows 和 Linux 不同,Windows 区分普通文件和套接字,并定义了专门的接收和发送的函数。

从服务器端发送数据使用 send() 函数,它的原型为:

int send(SOCKET sock, const char *buf, int len, int flags);

sock 为要发送数据的套接字,buf 为要发送的数据的缓冲区地址,len 为要发送的数据的字节数,flags 为发送数据时的选项。

返回值和前三个参数不再赘述,最后的 flags 参数一般设置为 0 或 NULL,初学者不必深究。

在客户端接收数据使用 recv() 函数,它的原型为:

int recv(SOCKET sock, char *buf, int len, int flags);
  • 12
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
### 回答1: c socket 通信代码通常包含以下几个部分: 1. 套接字的创建和初始化。在 c 中,可以使用 `socket()` 函数来创建一个套接字,并使用 `bind()` 函数来将其绑定到一个本地地址和端口上。 2. 连接到远程主机。如果要与远程主机进行通信,需要使用 `connect()` 函数来连接到远程主机。 3. 接收和发送数据。使用 `recv()` 和 `send()` 函数可以接收和发送数据。 4. 关闭套接字。使用 `close()` 函数可以关闭套接字。 以下是一个简单的 c socket 通信示例: ```c #include <stdio.h> #include <string.h> #include <sys/socket.h> #include <netinet/in.h> int main() { // 创建套接字 int sockfd = socket(AF_INET, SOCK_STREAM, 0); // 初始化服务器地址 struct sockaddr_in server_addr; memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = INADDR_ANY; server_addr.sin_port = htons(12345); // 绑定套接字 bind(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)); // 监听套接字 listen(sockfd, 5); // 接受客户端连接 struct sockaddr_in client_addr; socklen_t client_addr_len = sizeof(client_addr); int client_sockfd = accept(sockfd, (struct sockaddr*)&client_addr, &client_addr_len); // 接收数据 char buffer[1024]; recv(client_sockfd, buffer, sizeof(buffer), 0); // 发送数据 send( ### 回答2: Socket是一种用于网络通信的编程接口,通过Socket可以在不同的计算机之间进行数据传输。使用C语言编写Socket通信代码可以实现网络通信功能。 以下是一个简单的C语言Socket通信代码示例: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <arpa/inet.h> int main() { int socket_desc, client_sock, c, read_size; struct sockaddr_in server, client; char message[2000], client_message[2000]; // 创建Socket socket_desc = socket(AF_INET, SOCK_STREAM, 0); if (socket_desc == -1) { printf("无法创建Socket\n"); return 1; } printf("Socket创建成功\n"); // 设置Socket参数 server.sin_family = AF_INET; server.sin_addr.s_addr = INADDR_ANY; server.sin_port = htons(8888); // 绑定Socket if (bind(socket_desc, (struct sockaddr *)&server, sizeof(server)) < 0) { printf("绑定失败\n"); return 1; } printf("绑定成功\n"); // 监听连接请求 listen(socket_desc, 3); // 等待客户端连接 printf("等待客户端连接...\n"); c = sizeof(struct sockaddr_in); client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t *)&c); if (client_sock < 0) { printf("接受连接请求失败\n"); return 1; } printf("客户端连接成功\n"); // 接收客户端消息并发送回复 while ((read_size = recv(client_sock, client_message, 2000, 0)) > 0) { client_message[read_size] = '\0'; printf("接收到客户端消息:%s\n", client_message); // 进行数据处理 // ... // 发送回复消息 strcpy(message, "收到你的消息了!"); write(client_sock, message, strlen(message)); } if (read_size == 0) { printf("客户端断开连接\n"); } else if (read_size == -1) { printf("接收消息失败\n"); } return 0; } ``` 以上代码实现了一个简单的Socket服务器端,它通过8888端口监听连接请求,并在接收到客户端消息后发送回复消息。代码中使用socket、bind、listenacceptSocket相关函数,通过这些函数可以创建、绑定、监听和接受连接请求,实现了基本的Socket服务器功能。在接收到客户端消息后,可以根据需求进行数据处理,并发送回复消息。 ### 回答3: C语言中使用socket进行通信的代码可以分为服务端和客户端两部分。 服务端代码如下: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> int main() { int serverSocket, clientSocket; struct sockaddr_in serverAddr, clientAddr; socklen_t addrLen = sizeof(struct sockaddr_in); char buffer[1024]; // 创建socket serverSocket = socket(AF_INET, SOCK_STREAM, 0); if (serverSocket == -1) { perror("socket error"); exit(1); } // 设置服务器地址 serverAddr.sin_family = AF_INET; serverAddr.sin_addr.s_addr = INADDR_ANY; serverAddr.sin_port = htons(8888); // 绑定socket到服务器地址 if (bind(serverSocket, (struct sockaddr *)&serverAddr, addrLen) == -1) { perror("bind error"); exit(1); } // 开始监听 if (listen(serverSocket, 5) == -1) { perror("listen error"); exit(1); } printf("Server running...\n"); // 接收客户端连接 clientSocket = accept(serverSocket, (struct sockaddr *)&clientAddr, &addrLen); if (clientSocket == -1) { perror("accept error"); exit(1); } // 接收客户端消息 memset(buffer, 0, sizeof(buffer)); if (recv(clientSocket, buffer, sizeof(buffer), 0) == -1) { perror("receive error"); exit(1); } printf("Received message from client: %s\n", buffer); // 关闭socket close(clientSocket); close(serverSocket); return 0; } ``` 客户端代码如下: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> int main() { int clientSocket; struct sockaddr_in serverAddr; char buffer[1024]; // 创建socket clientSocket = socket(AF_INET, SOCK_STREAM, 0); if (clientSocket == -1) { perror("socket error"); exit(1); } // 设置服务器地址 serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons(8888); serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 连接服务器 if (connect(clientSocket, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) == -1) { perror("connect error"); exit(1); } // 发送消息给服务器 memset(buffer, 0, sizeof(buffer)); strcpy(buffer, "Hello, server!"); if (send(clientSocket, buffer, sizeof(buffer), 0) == -1) { perror("send error"); exit(1); } // 关闭socket close(clientSocket); return 0; } ``` 以上就是一个简单的使用socket进行通信的C代码示例。服务端创建socket并监听客户端连接,接收客户端消息;客户端创建socket并连接服务器,发送消息给服务器。通过这样的方式,服务端和客户端可以进行数据的传输与通信。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值