服务器与服务器之间的全双工通信客户

时间:2012-03-09 07:38:53

标签: c multithreading sockets

我想为服务器和服务器之间的全双工通信制作代码。客户使用此代码。
我收到来自服务器端的接收消息线程错误&在客户端的发送消息线程中 请帮我解决这个错误&建议我是否需要进行任何其他更改。 谢谢:))

server.cpp

int newsockfd, n;

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

void* recvFn( void* data )
{
    char buffer[256];
    while(n==0){

    memset( buffer, sizeof(buffer), 0);
        n = recv(newsockfd,buffer,255,MSG_PEEK);
        if(n>0){
            printf("cliet: ");
            printf("%s",buffer);    
        }

    }
    return NULL;
}

void* sendFn( void* data )
{
    char temp[255], buffer[255];
    while(n==0){
    memset( buffer, sizeof(buffer), 0);
        fgets(temp,255,stdin);                  
        sprintf(buffer,"clent: %s",temp);
        n = send(newsockfd,buffer,strlen(buffer),MSG_EOR);
    }
    return NULL;
}
int main(int argc, char *argv[])
{
    int sockfd, portno;
    socklen_t clilen;

    struct sockaddr_in serv_addr, cli_addr;

    if (argc < 2) {
        fprintf(stderr,"ERROR, no port provided\n");
        exit(1);
    }

    pthread_t recvThread, sendThread;

    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) 
        error("ERROR opening socket");

memset( &serv_addr, sizeof(serv_addr), 0);
    portno = atoi(argv[1]);
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    serv_addr.sin_port = htons(portno);

    int on = 1;
    if ( setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof( on ) ) != 0 ) {
        close( sockfd );
        return -1;
    }


    if (bind(sockfd, (struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0) 
        error("ERROR on binding");

    listen(sockfd,5);

    clilen = sizeof(cli_addr);
    newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
    if (newsockfd < 0) 
        error("ERROR on accept");

        n = 0;
        int rc;

        rc = pthread_create( &recvThread, NULL, recvFn, NULL);
        if(rc){
            printf("error in receive-message thread\n");
            return -1;
        }


        rc = pthread_create( &sendThread, NULL, sendFn, NULL);
        if(rc){
            printf("error in send-message thread\n");
            return -1;
        }

        close(newsockfd);
        close(sockfd);
    pthread_cancel(recvThread);
    pthread_cancel(sendThread);
    return 0; 
}

client.cpp

int sockfd, n;

void* recvFn( void* data )
{
    char buffer[255];
    while( n==0 ){

    memset( buffer, sizeof(buffer), 0);
        n = recv(sockfd,buffer,255,MSG_PEEK);
        if(n>0){
            printf("server: ");
            printf("%s",buffer);    
        }
    }
    return NULL;
}

void* sendFn( void* data )
{
    char temp[255], buffer[255];
    while( n==0 ){
    memset( buffer, sizeof(buffer), 0);
        fgets(temp,255,stdin);                  
        sprintf(buffer,"clent: %s",temp);
        n = send(sockfd,buffer,strlen(buffer),MSG_EOR);

    }
    return NULL;
}

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

int main(int argc, char *argv[])
{
    int  portno;
    struct sockaddr_in serv_addr;
    struct hostent *server;
    char buffer[256];

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

    pthread_t recvThread, sendThread;


    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) 
        error("ERROR opening socket");

    portno = atoi(argv[2]);
    server = gethostbyname(argv[1]);
    if (server == NULL) {
        fprintf(stderr,"ERROR, no such host\n");
        exit(0);
    }

memset( &serv_addr, sizeof(serv_addr), 0);
    serv_addr.sin_family = AF_INET;
memcpy((char *)server->h_addr,(char *)&serv_addr.sin_addr.s_addr, server->h_length);
    serv_addr.sin_port = htons(portno);  
    if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0) 
        error("ERROR on connecting");

        n = 0;
        int rc;
        rc = pthread_create( &sendThread, NULL, sendFn, NULL);
        if(rc){
            printf("error in send-message thread\n");
            return -1;
        }

        rc = pthread_create( &recvThread, NULL, recvFn, NULL);
        if(rc){
            printf("error in receive-message thread\n");
            return -1;
        }

        close(sockfd);
    pthread_cancel(recvThread);
    pthread_cancel(sendThread);
    return 0;
}

1 个答案:

答案 0 :(得分:1)

您的pthread_mutex操作完全没有意义。除了n之外,你只引用互斥锁内的局部变量,其中应该在每个线程中是本地的,newsockfd也不应该是全局的,见下文。 (难道你不认为调用recv的函数应该有一个局部变量来捕获读取的字节数,而不是与其他线程全局共享那个愚蠢的小临时变量吗?)

你的主线程处于while循环中,创建疯狂的线程。此外,在该循环内部,它在创建线程后立即关闭了一个且只接受了套接字。

你好忘了将accept放在循环中。显然。

此外,您似乎认为主循环将以某种方式等待线程对在启动新线程之前终止。您缺少pthread_join次调用以等待线程完成通信。如果您希望线程在主循环使用新线程接受新连接时继续运行,则应该使用pthread_detached或使用线程创建属性将这些线程分离,这会使它们分离。非pthread_join编译的非分离线程继续占用资源。

说到关闭,线程在n == 0期间保持循环的确是正确的条件吗?只要其中一个线程将n设置为非零,就会满足关闭条件。但是非零值是正常的:写入或读取一些字节。当套接字上出现致命的接收错误或读取返回零时,您的读者应终止循环。

另外,您正在评估互斥体之外的n == 0

如果要接受多个并发连接,每个连接都有一对线程,那么就不能使用单个全局套接字。你必须给每对线程自己的套接字。每对中的两个线程不必使用互斥锁来共享套接字。套接字调用在内核中是线程安全的,并且线程不执行读取或写入操作;一个是阅读,一个是写作。

其他问题

您的发件人不断发送未初始化的垃圾:一个从未设置为包含任何数据的缓冲区。

在255个字节的数组上有一个256个字节的bzero

同时

请勿使用bzero(或bcopy等)。它是20世纪80年代的BSD主义。 C语言最终在1989年由ANSI标准化,并在不久之后于1990年由ISO标准化。那时,它已经有了库函数memsetmemcpymemmove

我认为22年后退休bcopy是安全的,dontcha认为?