Recv()不在单独的线程中工作,C套接字编程

时间:2016-03-14 18:29:24

标签: c multithreading sockets network-programming

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

以下是我服务器的代码:

#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)。这有效,我收到了数据包。然后我将程序的控制权发送给线程。然而,虽然&#34; rec&#34;变量正确传递信息,后续接收不起作用,并以小于0的值退出。

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

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

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

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

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

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

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

1 个答案:

答案 0 :(得分:0)

我不小心将接收设置为端口而不是套接字。我是假的。我知道很多人告诉我有关TCP约定的代码构造有多糟糕。我正在为一项作业建立代码,我无法对教授告诉我们这是做到这一点的方法。