полнодуплексная связь между сервером и клиентом - PullRequest
0 голосов
/ 09 марта 2012

Я хочу создать код для полнодуплексной связи между сервером и клиентом, используя этот код.
Я получил ошибку в цепочке получения сообщений со стороны сервера и в цепочке отправки сообщений со стороны клиента.
пожалуйста, помогитемне, чтобы решить эту ошибку и предложить мне, если какие-либо другие изменения необходимы.Спасибо:)

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 Ответ

1 голос
/ 09 марта 2012

Ваши pthread_mutex операции абсолютно бессмысленны.Вы имеете в виду только локальные переменные внутри блокировки мьютекса, отличные от n, которые должны быть локальными в каждом потоке и newsockfd, которые также не должны быть глобальными, см. Ниже.(Не думаете ли вы, что функция, которая вызывает recv, должна иметь локальную переменную для захвата количества прочитанных байтов и не делить эту маленькую глупую временную переменную глобально с другими потоками?)

Ваш основной потокнаходится в цикле, создавая темы, как сумасшедшие.Кроме того, внутри этого цикла он закрыл один-единственный принятый сокет сразу после создания потоков.

Вы, очевидно, забыли поместить свой accept в цикл.

Также вы, кажется, думаете, что основной цикл каким-то образом будет ожидать завершения пары потоков перед запуском новых.Вам не хватает pthread_join вызовов, чтобы дождаться окончания общения потоков.Если вы хотите, чтобы поток продолжал работать, пока основной цикл принимает новые соединения, используя новые потоки, вы должны отключить эти потоки с помощью pthread_detached или с помощью атрибута создания потока, который делает их отключенными.Неотсоединенные потоки, которые не pthread_join -ed, продолжают занимать ресурсы.

Говоря о завершении работы, действительно ли это правильное условие, что потоки продолжают цикл пока n == 0?Как только один из потоков устанавливает ненулевое значение n, выполняется условие отключения.Но ненулевое значение является нормальным: некоторые байты записаны или прочитаны.Ваш читатель должен прервать цикл, если в сокете возникла фатальная ошибка приема или чтение вернулось к нулю.

Кроме того, вы оцениваете n == 0 вне мьютекса!

Если выЕсли вы хотите принимать несколько одновременных соединений, каждое из которых имеет пару потоков, то вы не можете использовать один глобальный сокет.Вы должны дать каждой паре потоков свой сокет.Два потока в каждой паре не должны использовать мьютекс для совместного использования сокета.Вызовы сокетов поточно-ориентированы в ядре, и потоки не выполняют чтение или запись;один читает, а другой пишет.

Другие проблемы

Ваш отправитель продолжает отправлять неинициализированный мусор: буфер, который никогда не был настроен для хранения каких-либо данных.

У вас есть bzero из 256 байтов в массиве из 255 байтов.

Также

Не используйте bzero (или bcopy и т. Д.).Это BSD-изм с 1980-х годов.Язык C был окончательно стандартизирован в 1989 году ANSI и вскоре после этого в 1990 году ISO.В то время в нем уже были библиотечные функции memset, memcpy и memmove.

Я думаю, что 22 года спустя можно безопасно уйти в отставку bcopy, не думаешь?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...