c - TCP write() 将 char* 打印到自身而不是仅在第一个套接字连接上缓冲,但在第二个连接上工作正常

标签 c sockets tcp

在客户端第一次连接到服务器套接字时,服务器将输出打印给自己,并让客户端处于阻塞状态。但是第二个客户端开始接收服务器的输出。 预期输出到客户端的缓冲区是服务器正常运行时间。

为什么会这样,有没有办法立即将输出发送给Client而不阻塞?

要复制,请在一个终端上运行“ruptimeServer”,然后运行“ruptimeClient [localIPAddress] [serverIPAddress]”。

以下是服务器 I/O 的示例。

[user@linux-3 Lab2]$ ./ruptimeServer 
Awaiting connection.
 20:42:05 up 2 days, 17:38,  5 users,  load average: 0.00, 0.01, 0.06  <-- buffer
Write Success
Awaiting connection.
Write Success
Awaiting connection.
Write Success
Awaiting connection.
^CCaught Ctrl+C, closing all connections.

下面是客户端的 I/O。

[user@linux-3 Lab2]$ ./ruptimeClient 127.0.0.1 10.24.87.66
Connection Success.
^C
[user@linux-3 Lab2]$ ./ruptimeClient 127.0.0.1 10.24.87.66
Connection Success.
10.24.87.66:  20:42:14 up 2 days, 17:38,  5 users,  load average: 0.00, 0.01, 0.06
[user@linux-3 Lab2]$ ./ruptimeClient 127.0.0.1 10.24.87.66
Connection Success.
10.24.87.66:  20:42:18 up 2 days, 17:38,  5 users,  load average: 0.00, 0.01, 0.06

下面是服务器的代码。

#include <stdio.h>
#include <stdlib.h>
#include <sys/sysinfo.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <signal.h>
#include <sys/select.h>

char* get_uptime();
void sig_handl(int sig_num);
int sersock, consock;
int main(int argc, char* argv[]){
    struct sockaddr_in serveraddr, clientaddr;
    struct sigaction sigIntHandler;
    int on = 1;

    sigIntHandler.sa_handler = sig_handl;
    sigemptyset(&sigIntHandler.sa_mask);
    sigIntHandler.sa_flags = 0;

    char input_buffer[1024] = {0};
    int len = sizeof(clientaddr);

    char* IP_ADDRESS = "192.168.254.11";

    if((sersock = socket(PF_INET, SOCK_STREAM, 0)) < 0){
        perror("socket() error");
        exit(1);
    }

    serveraddr.sin_family = PF_INET;
    serveraddr.sin_port = htons(28189);
    serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
    if(bind(sersock, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0){
        perror("bind() error");
        exit(1);
    }
    if(listen(sersock, 10) < 0){
        perror("listen() error");
        exit(1);
    }
    char *output;
    output = malloc(sizeof(char) * 1024);
    signal(SIGINT, sig_handl);
    while(1){
        printf("Awaiting connection.\n");
        if(consock = accept(sersock, (struct sockaddr *)&clientaddr, &len) < 0){
            perror("accept() error");
            exit(1);
        }
        output = get_uptime();
        if(write(consock, output, 1024) < 0){
            perror("write() error");
            exit(1);
        }
        printf("Write Success\n");
        close(consock);
    }
    close(sersock); 
}

char * get_uptime(){        //returns uptime on server
    char *buffer;
    buffer = malloc(sizeof(char) * 1024);
    FILE* file = popen("uptime", "r");
    fgets(buffer, 100, file);
    pclose(file);

    return buffer;
}

void sig_handl(int sig_num){
    printf("Caught Ctrl+C, closing all connections.\n");
    close(consock);
    close(sersock);
    exit(0);
}

下面是客户端的代码。

#include <stdio.h>
#include <stdlib.h>
#include <sys/sysinfo.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/select.h>

int main(int argc, char* argv[]){
    if(argc != 3){
        printf("Not enough arguments. To run, \"./ruptimeClient <localhost_IP> <server_IP>\"\n");
        return 0;
    }
    struct sockaddr_in remoteaddr;
    char input_buffer[100];
    //input_buffer = malloc(sizeof(char) * 100);
    int clisock;
    char* SERVER_IP = argv[2];

    if((clisock = socket(PF_INET, SOCK_STREAM, 0)) < 0){
        perror("socket() error");
        exit(1);
    }

    remoteaddr.sin_family = PF_INET;
    remoteaddr.sin_port = htons(28189);
    remoteaddr.sin_addr.s_addr = inet_addr(SERVER_IP);

    if(connect(clisock, (struct sockaddr *)&remoteaddr, sizeof(remoteaddr)) < 0){
        perror("Connection failed");
        exit(1);
    }
    printf("Connection Success.\n");
    if(read(clisock, input_buffer, 100) < 0){
        perror("read() error");
        exit(1);
    }
    //input_buffer = "test";
    printf("%s: %s", SERVER_IP, input_buffer);
    close(clisock);
    return 0;
}

最佳答案

问题出在这里:

if(consock = accept(sersock, (struct sockaddr *)&clientaddr, &len) < 0){

这被解析为就好像你这样写:

if(consock = (accept(sersock, (struct sockaddr *)&clientaddr, &len) < 0)){

因此,consock 最终设置为 0,当它被解释为文件描述符时,意味着标准输入。然后它在第一个客户端(挂起的客户端)之后关闭,因此它可供后续客户端使用,然后重新分配现在可用的 FD 编号。要修复它,请添加显式括号,如下所示:

if((consock = accept(sersock, (struct sockaddr *)&clientaddr, &len)) < 0){

关于c - TCP write() 将 char* 打印到自身而不是仅在第一个套接字连接上缓冲,但在第二个连接上工作正常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57983971/

相关文章:

c++ - 导出对象后何时释放 dll

node.js - 如何使用 Node.js/Express + Passport + Websockets 进行身份验证?

c - 线程 C 客户端-服务器聊天应用程序中 SIGSEGV 的未知原因

sockets - 只能通过 TCP 接收或发送

java - 如何通过静态IP地址连接apache ignite节点

python - YCM 没有找到我的标题?

c - C 中的合并排序算法未按预期工作

c - Ruby-FFI 在包装以大写字母开头的函数时生成常量?

java - 有没有办法在不关闭底层流的情况下关闭 Writer?

c# - 写入服务器的不同数据被附加为单个字符串