UDP套接字和线程问题

时间:2019-05-03 00:51:30

标签: c multithreading sockets udp

我遇到了UDP套接字的问题。

对于此特定程序,单个.c文件既需要是另一台服务器的客户端(通过TCP),又必须是其自身的服务器/客户端(执行两次,在单独的服务器上运行)。它将同时运行两次,因为它需要能够同时完成TCP连接(针对一种数据类型)和UDP连接(针对另一种数据类型)与线程或叉子,但我使用线程。

我遇到的问题是UDP套接字没有从彼此接收任何数据报。没有编译错误并且运行正常,但是除了常规的调试打印语句外没有任何输出。它卡在了recvfrom命令上。

下面的代码分为两部分(同样,在同一.c文件中)。顶部是服务器部分,下部是客户端部分。这一切都在一个线程内完成。我尝试创建套接字,然后使用客户端代码调用线程(想法是线程可以与父代通信,但这没关系),但是得到的结果是相同的。因此,目前,该线程仅处理UDP连接,而父级处理TCP。

如果您需要更多说明,请随时提问。这是用于学校作业,所以我不能给太多,但我会说我能做的。

谢谢!

快速编辑:下面所有这些代码所做的只是向服务器发送问候,然后再向客户端发送问候。不需要更多详细信息。

假设argv->stuff是我传递给线程的结构,并且用户在执行时提供了服务器,IP地址和端口。

//----- Server portion of code is below

int cli2_sockfd; 
char buffer_cli2[MAXLINE]; 
char *hello2 = "Hello from client 2"; 
struct sockaddr_in cli2_addr, client1_addr; 
int clis_portno = atoi(argv->port);
clis_portno = clis_portno + 1;

// Creating socket file descriptor 
if ( (cli2_sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) { 
    perror("socket creation failed"); 
    exit(EXIT_FAILURE); 
} 

memset(&cli2_addr, 0, sizeof(cli2_addr)); 
memset(&client1_addr, 0, sizeof(client1_addr)); 

// Filling server information 
cli2_addr.sin_family = AF_INET; // IPv4 
cli2_addr.sin_addr.s_addr = INADDR_ANY; 
cli2_addr.sin_port = htons(clis_portno); 

// Bind the socket with the server address 
if ( bind(cli2_sockfd, (const struct sockaddr *)&cli2_addr, 
        sizeof(cli2_addr)) < 0 ) 
{ 
    perror("bind failed"); 
    exit(EXIT_FAILURE); 
} 

while(1)
{
    int n2;
    socklen_t len2;
    if((n2 = recvfrom(cli2_sockfd, (char *)buffer_cli2, MAXLINE, 
                0, ( struct sockaddr *) &client1_addr, 
                &len2)) < 0)
    {
        perror("svr recvfrom");
        exit(EXIT_FAILURE);
    }

    buffer_cli2[n2] = '\0'; 
    printf("Client 1: %s\n", buffer_cli2); 

    if(sendto(cli2_sockfd, (const char *)hello2, strlen(hello2), 
        MSG_CONFIRM, (const struct sockaddr *) &client1_addr, 
            len2) < 0)
    {
        perror("svr sendto");
        exit(EXIT_FAILURE);
    }
    printf("Hello message sent.\n"); 
}


//----- The client portion of the code is below


int client1_sockfd; 
char buffer[MAXLINE]; 
char *hello1 = "Hello from client 1"; 
struct sockaddr_in   client2_addr; 
struct hostent *client_2;
clis_portno = atoi(argv->port);
clis_portno = clis_portno + 1;

// Creating socket file descriptor 
if ( (client1_sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) { 
    perror("socket creation failed"); 
    exit(EXIT_FAILURE); 
} 

memset(&client2_addr, 0, sizeof(client2_addr)); 

if((client_2 = gethostbyname(argv->name)) == NULL)
{
    perror("cli gethostbyname");
    exit(EXIT_FAILURE);
}

bzero((char *) &client2_addr, sizeof(client2_addr));

// Filling Client 2 information 
client2_addr.sin_family = AF_INET; 
bcopy((char *)client_2->h_addr, (char *)&client2_addr.sin_addr.s_addr, client_2->h_length);
client2_addr.sin_port = htons(clis_portno); 

while(1)
{
    int n1;
    socklen_t len1;

    if( sendto(client1_sockfd, (const char *)hello1, strlen(hello1), 
        0, (const struct sockaddr *) &client2_addr, 
            sizeof(client2_addr)) < 0)
    {
        perror("cli sendto");
        exit(EXIT_FAILURE);
    }

    printf("IN THREAD: Hello1 = %s\n", hello1); 

    if((n1 = recvfrom(client1_sockfd, (char *)buffer, MAXLINE, 
                MSG_WAITALL, (struct sockaddr *) &client2_addr, 
                &len1)) < 0)
    {
        perror("cli recvfrom");
        exit(EXIT_FAILURE);
    }

    buffer[n1] = '\0'; 
    printf("IN THREAD: Client 2 : %s\n", buffer); 
}

2 个答案:

答案 0 :(得分:0)

您忘记初始化len2

socklen_t len2;
if((n2 = recvfrom(cli2_sockfd, (char *)buffer_cli2, MAXLINE, 
            0, ( struct sockaddr *) &client1_addr, 
            &len2)) < 0)

更好:

socklen_t len2 = sizeof(client1_addr);
n2 = recvfrom(cli2_sockfd, (char *)buffer_cli2, MAXLINE, 
        0, ( struct sockaddr *) &client1_addr, 
        &len2));
if (n2 < 0)
{
   ….

不确定这是否是阻止接收数据包的唯一问题。

答案 1 :(得分:0)

我稍微清理了一下代码,并使用服务器的端口9999使其正常工作。并让客户端连接到本地主机。我清理了gethostbyname周围的一些memcpy语句,一些结构初始化调用,并删除了可能因良性错误(包括服务器脱机时的recvfrom错误)而发生的一些exit调用。 MSG_WAITALL标志看起来很奇怪,所以我也将其删除。

我使Cygwin正常运行,没有任何特殊的技巧。我毫不怀疑它将在Linux(或任何Unix)上运行。

您可以看到它在服务器模式下可以正常工作:

enter image description here

以及客户端模式下的相应窗口:

enter image description here

此处的代码:

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/time.h>
#include <stdlib.h>
#include <memory.h>
#include <ifaddrs.h>
#include <net/if.h>
#include <stdarg.h>

#define MAXLINE 260
#define MSG_CONFIRM "Confirm"

void server(unsigned short port)
{
    int cli2_sockfd = -1;
    char buffer_cli2[MAXLINE] = { 0 };
    char *hello2 = "Hello from client 2";
    struct sockaddr_in cli2_addr = { 0 }, client1_addr = { 0 };
    unsigned short clis_portno = port;

    // Creating socket file descriptor 
    if ((cli2_sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        perror("socket creation failed");
        exit(EXIT_FAILURE);
    }

    // Filling server information 
    cli2_addr.sin_family = AF_INET; // IPv4 
    cli2_addr.sin_addr.s_addr = INADDR_ANY;
    cli2_addr.sin_port = htons(clis_portno);

    // Bind the socket with the server address 
    if (bind(cli2_sockfd, (const struct sockaddr *)&cli2_addr,
        sizeof(cli2_addr)) < 0)
    {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }

    while (1)
    {
        int n2;
        socklen_t len2 = sizeof(client1_addr);
        if ((n2 = recvfrom(cli2_sockfd, (char *)buffer_cli2, MAXLINE,
            0, (struct sockaddr *) &client1_addr,
            &len2)) < 0)
        {
            perror("svr recvfrom");
            exit(EXIT_FAILURE);
        }

        buffer_cli2[n2] = '\0';
        printf("Client 1: %s\n", buffer_cli2);

        if (sendto(cli2_sockfd, (const char *)hello2, strlen(hello2),
            0, (const struct sockaddr *) &client1_addr,
            len2) < 0)
        {
            perror("svr sendto");
        }
        printf("Hello message sent.\n");

    }
}

void client(const char* hostname, unsigned short port)
{
    int client1_sockfd;
    char buffer[MAXLINE];
    char *hello1 = "Hello from client 1";
    struct sockaddr_in   client2_addr = { 0 };
    struct hostent *client_2 = NULL;
    unsigned short clis_portno = port;

    // Creating socket file descriptor 
    if ((client1_sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        perror("socket creation failed");
        exit(EXIT_FAILURE);
    }

    if ((client_2 = gethostbyname(hostname)) == NULL)
    {
        perror("cli gethostbyname");
        exit(EXIT_FAILURE);
    }

    // Filling Client 2 information 
    client2_addr.sin_family = AF_INET;
    client2_addr.sin_port = htons(clis_portno);
    memcpy(&client2_addr.sin_addr, client_2->h_addr, 4);

    while (1)
    {
        int n1;


        if (sendto(client1_sockfd, (const char *)hello1, strlen(hello1),
            0, (const struct sockaddr *) &client2_addr,
            sizeof(client2_addr)) < 0)
        {
            perror("cli sendto");
            exit(EXIT_FAILURE);
        }

        printf("IN THREAD: Hello1 = %s\n", hello1);

        socklen_t len1 = sizeof(client2_addr);
        if ((n1 = recvfrom(client1_sockfd, (char *)buffer, MAXLINE,
            0, (struct sockaddr *) &client2_addr,
            &len1)) < 0)
        {
            perror("cli recvfrom");
        }
        else
        {
            buffer[n1] = '\0';
            printf("IN THREAD: Client 2 : %s\n", buffer);
        }
        sleep(1);
    }
}




int main(int argc, char** argv)
{

    if ((argc > 1) && (strcmp(argv[1], "s") == 0))
    {
        printf("Running in server mode\n");
        server(9999);
    }
    else
    {
            printf("Running in client mode\n");
            client("localhost", 9999);
    }
    return 0;
}