【问题标题】:Recv() not working in separate thread, C socket programmingRecv() 不在单独的线程中工作,C 套接字编程
【发布时间】:2016-06-29 22:44:09
【问题描述】:

我在使用线程的 C 程序中返回 -1 的 recv() 函数存在一些问题。该程序的基础是在一个线程中接收一些请求数据包,并让第二个线程向所有注册的客户端发送多播。

下面是我的服务器的代码:

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

#define SERVER_PORT 5654
#define MAX_LINE 256
#define MAX_PENDING 5

/*structure of the packet*/
struct packet{
    short type;
    char data[MAX_LINE];
};
struct data_packet{
    short header;
    char data[MAX_LINE];
};
/* structure of Registration Table */
struct registrationTable{
    int port;
    char name[MAX_LINE];
    int req_no;
};
struct global_table{
    int sockid;
    int reqno;
};

void *join_handler(struct global_table *rec){

    int new_s;
    struct packet packet_reg;
    new_s = rec->sockid;


    printf("In thread: %i\n",new_s);
    printf("In thread: %i\n",rec->reqno);

    if(recv(new_s,&packet_reg,sizeof(packet_reg),0)<0){
        printf("\ncouldnt receive first reg packet\n");
        exit(1);
    }


    pthread_exit(NULL);
}
int main(int argc, char* argv[])
{
    /* initilizing all of the packets*/
    struct packet packet_reg;
    struct registrationTable table[10];
    struct global_table record[20];
    struct sockaddr_in sin;
    struct sockaddr_in clientAddr;
    char buf[MAX_LINE];
    int s, new_s;
    int len;
    int i;
    struct hostent *he;
    struct in_addr **addr_list;
    pthread_t threads[2];

    /* setup passive open */
    if((s = socket(PF_INET, SOCK_STREAM, 0)) < 0){
        perror("tcpserver: socket");
        exit(1);
    }

    /* build address data structure */
    bzero((char*)&sin, sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = INADDR_ANY;
    sin.sin_port = htons(SERVER_PORT);

    if(bind(s,(struct sockaddr *)&sin, sizeof(sin)) < 0){
        perror("tcpclient: bind");
        exit(1);
    }
    listen(s, MAX_PENDING);

    /* wait for connection, then receive and print text */
    while(1){

        if((new_s = accept(s, (struct sockaddr *)&clientAddr, &len)) < 0){
            perror("tcpserver: accept");
            exit(1);
        }
        /* print the port of the client*/
        printf("\n Client's port is %d \n", ntohs(clientAddr.sin_port)); 

        /* receive the first registration packet*/
        if(recv(new_s,&packet_reg,sizeof(packet_reg),0)<0){
            printf("\ncouldnt receive first reg packet\n");
            exit(1);
        }

        struct global_table client_info;

        client_info.sockid = ntohs(clientAddr.sin_port);
        client_info.reqno = 1;

        pthread_create(&threads[0],NULL,join_handler, &client_info);

    }

}

客户:

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

#define SERVER_PORT 5654
#define MAX_LINE 256

/*structure of the packet*/
struct packet{
    short type;
    char data[MAX_LINE];
};
struct data_packet{
    short header;
    char data[MAX_LINE];
};
int main(int argc, char* argv[])
{

    struct packet packet_reg;
    struct hostent *hp;
    struct sockaddr_in sin;
    char *host;
    char buf[MAX_LINE];
    int s;
    int len;
    char hostname[1024];
    hostname[1023] = '\0';

    if(argc == 2){
        host = argv[1];
    }
    else{
        fprintf(stderr, "usage:newclient server\n");
        exit(1);
    }

    /* translate host name into peer's IP address */
    hp = gethostbyname(host);
    if(!hp){
        fprintf(stderr, "unkown host: %s\n", host);
        exit(1);
    }

    /* active open */
    if((s = socket(PF_INET, SOCK_STREAM, 0)) < 0){
        perror("tcpclient: socket");
        exit(1);
    }

    /* build address data structure */
    bzero((char*)&sin, sizeof(sin));
    sin.sin_family = AF_INET;
    bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length);
    sin.sin_port = htons(SERVER_PORT);


    if(connect(s,(struct sockaddr *)&sin, sizeof(sin)) < 0){
        perror("tcpclient: connect");
        close(s);
        exit(1);
    }
    /* main loop: get and send lines of text
       all you have to do to start the program is
       enter any key */
    while(fgets(buf, sizeof(buf), stdin)){

        /* Find the hostname and print it*/
        gethostname(hostname, 1023);
        printf("Hostname: %s\n", hostname);

        /* populate the info for the first registration packet*/
        packet_reg.type = htons(121);
        strcpy(packet_reg.data,hostname);

        /*send the registration packet to the server*/
        if(send(s,&packet_reg,sizeof(packet_reg),0)<0){
            printf("\nsend failed\n");
            exit(1);
        }

        /* Print the contents of the first registration packet*/
        printf("Sent 1st reg packet data: %s\n",packet_reg.data );
        printf("Sent 1st reg packet type: %i\n",ntohs(packet_reg.type));

        /* create the second registration packet.
           I created separate packets for this so
           it was clearer*/
        packet_reg.type = htons(121);
        strcpy(packet_reg.data,hostname);

        /*send the second registration packet to the server*/
        if(send(s,&packet_reg,sizeof(packet_reg),0)<0){
            printf("\nsend  failed\n");
            exit(1);
        }

        /* Print the contents of the second registration packet*/
        printf("Sent 2nd reg packet data: %s\n",packet_reg.data );
        printf("Sent 2nd reg packet type: %i\n",ntohs(packet_reg.type));
    }
}

所以基本上,我正在创建连接并等待接收第一个注册数据包(packet_reg)。这有效,我收到了数据包。然后我将程序的控制权发送给线程。然而,虽然“rec”变量正确传递了信息,但后续的接收不起作用,并以小于 0 的值退出。

其他信息:数据包发送和接收都正确,但是客户端的端口,打印自

 printf("\n Client's port is %d \n", ntohs(clientAddr.sin_port)); 

被列为 0。我不确定这是否是一个问题,但是当所有接收都在主函数中时,代码可以正常工作。

另一个问题可能是我收到以下警告:

passing argument 3 pf pthread_create from incompatible pointer type expected    'void * (*) (void *)' but argument of type 'void * (*) (struct  global_table*)'

我已经研究过这个警告并且知道它与接收数据为无效然后强制转换有关。但是,当我从那里打印进行检查时,数据正在正确地发送到线程。

基本上,问题在于,虽然我可以使用相同的语句从线程外部的客户端接收数据包,但当我在线程内部时,数据包不会被接收并且 recv() 返回 -1。

【问题讨论】:

  • 如果像 recv 这样的调用返回失败 (-1) 那么您需要检查 errno 以查看实际错误是什么。
  • TCP 编程所有错误的集合。 bzero 调用,未能在accept() 调用中初始化sockaddr_in 的大小,未能注意TCP 是面向流的协议。经典。
  • 一个大问题是你将相同的指针传递给所有线程到相同的结构。因此,如果您有两个(或更多)客户端连接得足够快,那么所有线程将使用相同的结构并可能复制相同的套接字。 (并且您不会关闭导致资源泄漏的套接字。)
  • join_handler()为什么取这个名字?-S
  • 不要指望recv() 会收到它被告知的那么多。仔细阅读文档。

标签: c multithreading sockets network-programming


【解决方案1】:

我不小心将接收设置为端口而不是套接字。我是个假人。我知道你们中的很多人都告诉我关于 TCP 约定的代码构造有多糟糕。我正在为一项作业构建代码,但教授告诉我们这是完成它的方法,我无能为力。

【讨论】:

    猜你喜欢
    • 2021-05-11
    • 2013-11-06
    • 2013-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-08
    • 1970-01-01
    相关资源
    最近更新 更多