【问题标题】:read syscall returns trash and reads more times than write syscall writes in a socket读取系统调用返回垃圾并读取比写入系统调用在套接字中写入的次数更多
【发布时间】:2021-08-17 08:44:37
【问题描述】:

我想实现一个 fork 并执行一个新进程的程序。然后,父进程将多次写入套接字,子进程(执行)将从套接字读取写入发送的全部数据。问题是有时当我运行程序时,子进程读取 4501 次或更多并打印垃圾,而父进程只写入 4500。 这不会一直发生,所以我怀疑某处可能有一个统一变量。

父进程:

#include <stdio.h>
#include <sys/wait.h>        
#include <sys/types.h>       
#include <sys/socket.h>      
#include <netinet/in.h>      
#include <netdb.h>           
#include <unistd.h>          
#include <stdlib.h>         
#include <ctype.h>           
#include <signal.h>
#include <string.h>

typedef char * String;

void perror_exit(char *message);


int getSocketWrite(int portWrite){
    struct hostent *remWrite;
    struct sockaddr *serverptrWrite = NULL;
    struct sockaddr_in serverWrite;
    int sockWrite;
    serverptrWrite = (struct sockaddr*)&serverWrite;

    if ((sockWrite = socket(AF_INET, SOCK_STREAM, 0)) < 0)
        perror_exit("socket");

    if (setsockopt(sockWrite, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)) < 0)             //To reuse port if program exits.
        perror("setsockopt(SO_REUSEADDR) failed");


    char hostname[256];
    gethostname(hostname, 256);
    if ((remWrite = gethostbyname(hostname)) == NULL) { 
       herror("gethostbyname"); 
       exit(1);
    }
    serverWrite.sin_family = AF_INET;       
    memcpy(&serverWrite.sin_addr, remWrite->h_addr, remWrite->h_length);
    serverWrite.sin_port = htons(portWrite);    

    while (connect(sockWrite, serverptrWrite, sizeof(serverWrite)) < 0);
    return sockWrite;
}

void main(int argc, char *argv[]) {
    int             portWrite, sockWrite, i;
    int buffsize = 256;
    char            buf[buffsize];

    struct sockaddr_in serverWrite;
    struct sockaddr *serverptrWrite = NULL;
    struct hostent *remWrite = NULL;

    portWrite = 8080;

    pid_t pid = fork();
    if(pid == 0){
        execl("./server", "server");
        exit(1);
    }   
    else if(pid < 0){
        perror("error in fork");
    }
    
    sockWrite = getSocketWrite(portWrite);

    printf("Connecting to %s port %d\n", "Lenovo", portWrite);
    for(int i = 0; i < 4500; i++){
        memset(buf, 0, buffsize);
        strcpy(buf,"Test");
        write(sockWrite, buf, buffsize);
    }
    close(sockWrite);

}                

void perror_exit(char *message){
    perror(message);
    exit(EXIT_FAILURE);
}

server.c:

#include <stdio.h>
#include <sys/wait.h>        
#include <sys/types.h>       
#include <sys/socket.h>      
#include <netinet/in.h>      
#include <netdb.h>           
#include <unistd.h>          
#include <stdlib.h>         
#include <ctype.h>           
#include <signal.h>
#include <string.h>

typedef char * String;

void perror_exit(char *message);

int getSocketRead(int portRead){
    struct sockaddr_in serverRead;
    struct sockaddr *serverptrRead;
    int sockRead;
    serverptrRead = (struct sockaddr*)&serverRead;


    if ((sockRead = socket(AF_INET, SOCK_STREAM, 0)) < 0){
        perror("socket");
        exit(1);
    }
    if (setsockopt(sockRead, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)) < 0)             //To reuse port if program exits.
        perror("setsockopt(SO_REUSEADDR) failed");


    serverRead.sin_family = AF_INET;       
    serverRead.sin_addr.s_addr = htonl(INADDR_ANY);
    serverRead.sin_port = htons(portRead);      
    if (bind(sockRead, serverptrRead, sizeof(serverRead)) < 0){
        perror("bind");
        exit(1);
    }

    if (listen(sockRead, 5) < 0) {
        perror("listen"); 
        exit(1);
    }
    printf("Listening for connections to port %d\n", portRead);

    return sockRead;
}


int main(int argc, char *argv[]) {
    int buffsize = 256;
    char buffer[buffsize];

    int portRead, sockRead, newsock;
    struct sockaddr_in serverRead, clientRead;
    socklen_t clientlen = 0;

    struct sockaddr *serverptrRead = NULL;
    struct sockaddr *clientptrRead = NULL;


// //////////////////////////////////////////////////////////////////////////////////////////

    portRead = 8080;

    sockRead = getSocketRead(portRead);

    if ((newsock = accept(sockRead, clientptrRead, &clientlen)) < 0) {
        perror("accept");
        exit(1);
    }
    int count = 0;
    int bytes = 0;
    memset(buffer, 0, buffsize);

    while ((bytes = read(newsock, buffer, buffsize)) > 0){
        count++;
        buffer[bytes] = '\0';
        printf("%s %d bytes\n", buffer, bytes);
    }
    close(sockRead);

    printf("Count = %d\n",count);
}



void perror_exit(char *message){
    perror(message);
    exit(EXIT_FAILURE);
}

我在运行程序的 5 次中大约有 1 次出现错误。 奇怪的是,当我每 500 次使用 sleep(1) 时,我写了大约 该程序似乎运行良好。

【问题讨论】:

  • "子进程读取 4501 次或更多"。这是完全不足为奇的行为。对于 TCP 等基于流的协议,每个 read 不能保证准确接收使用单个 write 发送的内容。
  • reader读取的总字节数是否等于writer写入的总字节数?
  • 我怎样才能得到每一次写入的确切信息?有没有可能我做不到?
  • No 当我得到错误读取返回随机字节数但如果我得到错误字节总是低于 buffsize。

标签: c sockets system-calls


【解决方案1】:

我终于找到了问题,但我不太明白为什么会发生这种情况。 有时 read 返回的字节数少于参数中给出的字节数,当它返回时,我读取其余字节并将它们附加到我的变量中。 我的问题是,为什么 read() 读取的字节数少于给定的字节数。我也试过这个 管道和 read() 总是返回预期的结果(给读取的字节)

还有为什么 write() 总是写入预期的字节数?

【讨论】:

  • 我亲吻我心爱的 Pourekka 帮助我找到解决方案
猜你喜欢
  • 1970-01-01
  • 2017-04-16
  • 1970-01-01
  • 1970-01-01
  • 2018-07-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-01
相关资源
最近更新 更多