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

标签 c multithreading sockets network-programming

我在使用线程的 C 程序中 recv() 函数返回 -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)。这有效,我收到了数据包。然后我将程序的控制权发送给线程。然而,虽然“rec”变量正确传递了信息,但随后的接收不起作用并以小于 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。

最佳答案

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

关于c - Recv() 不在单独的线程中工作,C 套接字编程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35995263/

相关文章:

c - 初始化变量导致 printf 停止工作

c - 重新分配() : invalid next size in C

c++ - C编译器如何执行这个printf语句?

javascript - HTML5 音频的最大套接字

c - 网络编程通过c编译执行但不打印IP地址...!

c - 如何使用 C 在 Berkeley DB 中将整数值分配给 "key.data"

c++ - 英特尔 Pin 主线程

c++ - 在 c++/c 中利用所有 4 个内核

java - 在具有单个 HTTP 请求的 servlet 线程上运行长时间运行的进程总是不好吗?

python - 向客户端发送视频帧