基于tcp的服务器端/客户端

详细的内容看这里,我就不复制了:

https://github.com/riba2534/TCP-IP-NetworkNote/blob/master/ch04/README.md

TCP/IP 协议栈共分为 4 层,可以理解为数据收发分成了 4 个层次化过程,通过层次化的方式来解决问题

实现基于 TCP 的服务器/客户端

代码:

hello_server

1{{#include ch04/hello_server.c}}

代码: hello_client

1{{#include ch04/hello_client.c}}

echo服务器/客户端

程序运行的基本方式:

1{{#include ch04/echo_server.c}}
1{{#include ch04/echo_client.c}}

FAQ

问: 我在在linux下使用socket进行tcp网络编程,如果client端调用了close(sock)函数,那么server端口的read函数会读取到什么?

答:

在Linux下使用socket进行TCP网络编程时,如果客户端调用了close(sock)函数,服务器端的read函数的行为取决于客户端关闭连接的方式和时机。

通常情况下,当客户端调用close(sock)函数时,会向服务器发送一个FIN包,表示客户端想要关闭连接。服务器收到FIN包后,会做出以下响应:

  1. 如果服务器已经读取了所有客户端发送的数据,那么read函数会返回0,表示已经到达文件末尾(EOF)。这意味着客户端已经关闭了连接,并且没有更多的数据可读。

  2. 如果服务器还没有读取完客户端发送的所有数据,那么read函数会继续读取剩余的数据,直到读取完所有数据或者遇到错误为止。在这种情况下,read函数会返回实际读取到的字节数。当所有数据读取完毕后,再次调用read函数会返回0,表示已经到达文件末尾(EOF)。

  3. 如果客户端在发送数据的过程中突然关闭了连接,那么服务器的read函数可能会返回一个错误,通常是ECONNRESET错误,表示连接被重置。

需要注意的是,如果客户端在关闭连接之前没有发送所有的数据,那么服务器可能会丢失一部分数据。为了确保数据的完整性,通常建议在关闭连接之前,先调用shutdown(sock, SHUT_WR)函数,告诉操作系统不再发送数据,然后再调用close(sock)函数关闭连接。

总之,服务器端的read函数在客户端关闭连接时的行为取决于具体的情况:

作为服务器端,需要正确处理这些不同的情况,以确保程序的正确性和鲁棒性。

问: 如何检测到 read函数返回一个错误, 例如是ECONNRESET?

在Linux系统中,当read函数返回错误时,会设置全局变量errno来指示具体的错误类型。你可以通过检查errno的值来判断是否发生了ECONNRESET错误。

下面是一个示例代码,演示了如何检测read函数返回的错误:

 1#include <stdio.h>
 2#include <stdlib.h>
 3#include <unistd.h>
 4#include <errno.h>
 5#include <string.h>
 6
 7ssize_t read_data(int sockfd, void *buf, size_t len) {
 8    ssize_t num_read = read(sockfd, buf, len);
 9    if (num_read == -1) {
10        if (errno == ECONNRESET) {
11            printf("Connection reset by peer\n");
12        } else {
13            perror("read");
14        }
15        return -1;
16    }
17    return num_read;
18}

在上面的代码中,read_data函数封装了read函数的调用。它检查read函数的返回值:

在实际使用时,你可以根据需要对read_data函数进行调用,并根据返回值进行相应的处理:

1char buffer[1024];
2ssize_t num_read = read_data(sockfd, buffer, sizeof(buffer));
3if (num_read == -1) {
4    // 处理错误情况
5} else if (num_read == 0) {
6    // 处理连接关闭的情况
7} else {
8    // 处理成功读取数据的情况
9}

通过检查read_data函数的返回值,你可以判断是否发生了错误,并根据具体的错误类型采取相应的处理措施。

总之,通过检查read函数的返回值和errno的值,你可以检测并处理read函数返回的错误,包括ECONNRESET错误。这样可以增强程序的健壮性和可靠性。