c - 使用带有线程的 C 套接字来读取和写入套接字时出现问题

标签 c multithreading sockets deadlock blocking

我想编写一个 TCP 服务器-客户端聊天,但是当我启动两个线程来读取和写入两侧的套接字时,我认为它们会互相阻塞。谁能帮我解决这个问题吗?

服务器代码:

/* A simple server in the internet domain using TCP the port number is passed as an argument */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>

struct server_args_runner{
    char buffer [256];
    int newsockfd;
    pthread_t tid;
    pthread_attr_t attr;
    //read/write attribute (read == 0 and write == 1)
        int rw;
};

void error(char *msg){
        perror(msg);
        exit(1);
}

void* server_runner_fun(void* args){
    // this is the chat part!
    // get args:
    int n;
    struct server_args_runner *sar = (struct server_args_runner*) args;
    if(sar->rw == 0){
    printf("server thread trys to read from socket...\n");
        //read-part
    while(1){
                bzero(sar->buffer, 256);
                n = read(sar->newsockfd, sar->buffer, 255);
                if (n < 0){
                        error("ERROR reading from socket");
                      }
        }
                printf("%s\n", sar->buffer);
    } else {
    printf("server thread trys to write to socket...\n");
    //write-part
    while(1){
                bzero(sar->buffer, 256);
                fgets(sar->buffer, 255, stdin);
                n = write(sar->newsockfd, sar->buffer, strlen((char *) &(sar->buffer)));
                if (n < 0){
                        error("ERROR writing to socket");
                }

    }
    }
}


int main(int argc, char *argv[]){
    //fd = filedescriptor
    int sockfd, portno, clilen;
    struct sockaddr_in serv_addr, cli_addr;
    int n;

    if (argc < 2){
        fprintf(stderr,"ERROR, no port provided\n");
        exit(1);
    }
    //socket(...) returns a descriptor
    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    if (sockfd == -1){
        error("ERROR opening socket");
    }
    printf("Socket created successfully.\n");
    bzero((char *) &serv_addr, sizeof(serv_addr));

    portno = atoi(argv[1]);

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    //htons(..) converts the short from hostbyteorder to networkbyteorder
    serv_addr.sin_port = htons(portno);

    if (bind(sockfd, (struct sockaddr *) &serv_addr,sizeof(serv_addr)) == -1){
        error("ERROR on binding");
    }
    printf("binding successfull on port %d\n", portno);

    listen(sockfd, 2);
    clilen = sizeof(cli_addr);
    printf("server is listening ...\n");

    struct server_args_runner server_write_t, server_read_t;
    server_write_t.newsockfd = accept(sockfd,(struct sockaddr *) &cli_addr, &clilen);
    printf("server accepted connection to client.\n");
    if (server_write_t.newsockfd < 0){
        error("ERROR on accept");
    }

    //initializing both server_threads
    pthread_attr_init(&server_write_t.attr);
    pthread_attr_init(&server_read_t.attr);
    server_write_t.rw = 1;
    server_read_t.rw = 0;
    bcopy(&server_write_t.newsockfd, &server_read_t.newsockfd, sizeof(server_write_t.newsockfd));
    pthread_create(&server_write_t.tid, &server_write_t.attr, server_runner_fun, &server_write_t);
    pthread_create(&server_read_t.tid, &server_read_t.attr, server_runner_fun, &server_read_t);

    pthread_join(server_write_t.tid, NULL);
    pthread_join(server_read_t.tid, NULL);

    return 0;
}

客户端代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <pthread.h>

struct client_args_runner{
        char buffer [256];
        int sockfd;
        pthread_t tid;
        pthread_attr_t attr;
        //read/write attribute (read == 0 and write == 1)
        int rw;
};


void error(char *msg){
    perror(msg);
    exit(0);
}

void* client_runner_fun(void* args){
        // this is the chat part!
        // get args:
        int n;
        struct client_args_runner *car = (struct client_args_runner*) args;
        if(car->rw == 0){
        printf("client thread trys to read from socket...\n");
    //read-part
        while(1){
                bzero(car->buffer, 256);
                n = read(car->sockfd, car->buffer, 255);
                if (n < 0){
                        error("ERROR reading from socket");
                          }
                }
                printf("%s\n", car->buffer);
        } else {
    printf("client thread trys to write to socket...\n");
        //write-part
        while(1){
                bzero(car->buffer, 256);
                fgets(car->buffer, 255, stdin);
                n = write(car->sockfd, car->buffer, strlen((char *) &(car->buffer)));
                if (n < 0){
                        error("ERROR writing to socket");
                }

        }
        }
}


int main(int argc, char *argv[]){

    int portno, n;
    struct sockaddr_in serv_addr;
    struct hostent *server;

    if (argc < 3){
        fprintf(stderr,"usage %s hostname port\n", argv[0]);
        exit(0);
    }

    portno = atoi(argv[2]);

    struct client_args_runner client_write_t, client_read_t;

    client_write_t.sockfd = socket(AF_INET, SOCK_STREAM, 0);
    bcopy(&client_write_t.sockfd, &client_read_t.sockfd,
                    sizeof(client_write_t.sockfd));
    if (client_write_t.sockfd == -1){
        error("ERROR on creating socket_file_descriptor");
    }
    printf("socket created successfully.\n");
    server = gethostbyname(argv[1]);
    printf("hostname is valid.\n");
    if(server == NULL){
        fprintf(stderr, "Error, no such host\n");
        exit(0);
    }
    bzero((char *) &serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;

        bcopy((char *) server->h_addr, (char *) &serv_addr.sin_addr.s_addr, server->h_length);
    serv_addr.sin_port = htons(portno);
    printf("before connecting to client..\n");
    if (connect(client_write_t.sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) == -1){
        error("ERROR connecting");
    }
    printf("client connected successfully to server.\n");

    //initializing both client_threads
        pthread_attr_init(&client_write_t.attr);
        pthread_attr_init(&client_read_t.attr);
        client_write_t.rw = 1;
        client_read_t.rw = 0;
    pthread_create(&client_write_t.tid, &client_write_t.attr, client_runner_fun, &client_write_t);
        pthread_create(&client_read_t.tid, &client_read_t.attr, client_runner_fun, &client_read_t);

        pthread_join(client_write_t.tid, NULL);
        pthread_join(client_read_t.tid, NULL);

        return 0;

}

最佳答案

客户端和服务器读取器中的 printf 都位于 while(1) 循环之外,因此您的客户端和服务器通信正常,只是您没有打印从套接字读取的任何内容。

关于c - 使用带有线程的 C 套接字来读取和写入套接字时出现问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43748479/

相关文章:

c - 通过 sscanf 解析 syslog 消息

c - 释放结构体双指针的正确方法

Delphi - 线程中的 WndProc() 从未被调用

ios - 什么是iOS sleep 功能

java - Android VpnService 保护存储在 native 代码中的套接字?

node.js - 对象 #<Namespace> 没有方法 'socket'

c - fgetpos/fsetpos 和 ftell/fseek 之间有什么区别

c - 为什么 C 程序(.exe)停止工作?

c# - 使用 COM 对象的后台 worker 仍然锁定 UI

linux - 确定我可以向文件句柄写入多少;将数据从一个 FH 复制到另一个