2016-11-15 105 views
0

我一直在试图设置一个简单的UDP聊天服务器来学习如何使自己的聊天室,对于初学者,我只是得到与共享客户端运行UDP服务器的挂起与服务器相同的IP /端口。客户端以结构形式发送数据。 有3种可能性,一个服务器应该期望,一个新的客户端加入,它认识到通过匹配命令JOIN,或者通过匹配命令QUIT来匹配客户端,或者通过匹配这两种匹配的消息...使用消息结构的UDP聊天服务器

这些命令存储在客户端以(ID,COM​​MAND,Domain/Port)形式发送的结构中。除非它是一条消息,否则它将是(ID,Domain/Port,Message)。我在我的代码中处理了哪些内容。

客户100%的工作,因为它提供给我作为一个来源,但我不能使用它,因为它是可执行的,所以问题来自我的服务器。我制作了一个调试工具来检查发生了什么问题,这似乎是客户端加入时的情况,并且我向客户证实我已经接受他,客户端永远不会收到确认网络,这是因为我没有格式化它正确。 它应该类似Received: <1 JOIN loki>然后Sent: <1 JOIN loki>其中带括号的3个变量是结构部分..但它不存储正确的域/端口部分的第二个字符串...所以当我运行调试工具时,我得到Received: <1 JOIN>SENT <1 JOIN>。 那么为什么它会这样做,就像我解析结构到我的缓冲区结构然后发送它。它怎么没有正确捕获域部分?

#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <arpa/inet.h> 
#include <netdb.h> 
#include <stdio.h> 
#include <unistd.h> 
#include <string.h> 
#include <stdlib.h> 
#define LOCAL_PORT 2317 
#define MAX_LEN 255 

struct message { 

    int cid;     /* Connection ID */ 

    char str1[MAX_LEN];   /* JOIN, QUIT, or client-domain-name */ 

    char str2[MAX_LEN];  /* user-string or client-domain-name */ 

}; 



int rcv_cid; 

int rc,sd; 

struct message my_msg, rcv_msg; 

char rcv_str1[MAX_LEN]; 

char rcv_str2[MAX_LEN]; 




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

    struct sockaddr_in servAddr; 
    int servLen = sizeof(servAddr); 
    int IDlist [] = {0,0,0,0,0,0,0,0,0,0} ; 
    int i=0; int port; 
    /* Socket Creation */ 
    if(argc < 3){ 
     printf("usage : ./chatServer <port#> <debug_option:0 or 1>\n"); 
     exit(1); 
    } 
    sd = socket(AF_INET, SOCK_DGRAM , 0); 
    if(sd<0) { 
     printf("%s , cannot open socket \n",argv[0]); 
     exit(1); 
    } 

    /* bind argv[1] server port */ 
    servAddr.sin_family = AF_INET; 
    servAddr.sin_addr.s_addr = htonl(INADDR_ANY); 
    /* bind argv[1] which is what the user provides */ 
     port = atoi(argv[1]); 
    servAddr.sin_port = htons(port); 

     rc= bind(sd, (struct sockaddr *) &servAddr , sizeof (servAddr)); 
if(rc <0){ 
    printf("%s: cannot bind port number %d \n", argv[0], port); 
    exit (1); 
} 
printf("%s: waiting for data on port UDP %d \n", argv[0], port); 

while(1) { 
    /* grab incoming request */ 
    rc = recvfrom(sd, &rcv_msg, MAX_LEN, 0, (struct sockaddr *) &servAddr, &servLen); 
    printf(" %s \n" , rcv_msg.str2); 
    if(atoi(argv[2]) == 1){ 
     printf("DEBUG: Receiving <%d %s %s>\n",rcv_msg.cid,rcv_msg.str1,rcv_msg.str2); 
    } 
    if(strcmp(rcv_msg.str1,"join") == 0) { 

     for(i =1; i< 11 ; i ++){ 
      if(IDlist[i] == rcv_msg.cid){ 
       rcv_msg.cid = i; 
       IDlist[i] = rcv_msg.cid; 
       break;} 
     } 



    /*   for(j = 0, j < 10 ; j ++){      */ 
    /*   if(IDlist[j] != IDlist [i]){    */ 

    my_msg.cid = i; 
    strcpy(my_msg.str1, "JOIN"); 
    strcpy(my_msg.str2, rcv_msg.str2);  

    if(atoi(argv[2]) == 1){ 
      printf("DEBUG: Sending <%d %s %s>\n",my_msg.cid,my_msg.str1,my_msg.str2); 
           } 

    rc = sendto(sd, &my_msg, sizeof(my_msg)+1, 0, 
      (struct sockaddr *) &servAddr, 
      sizeof(servAddr)); 
    /* compose a temp struct , then send it to each ID on the list except the one we just added */ 
    } 


if(strcmp(rcv_msg.str1,"QUIT") == 0) { 

    for(i=0;i<10 ; i++){ 
     if(rcv_msg.cid == IDlist[i]) 
      IDlist [i] = 0; 
    } 
    my_msg.cid = rcv_msg.cid; 
    strcpy(my_msg.str1, "QUIT"); 
    strcpy(my_msg.str2, rcv_msg.str2); /*my name Nodname contains domain and port number built into C library */ 

if(atoi(argv[2]) == 1){ 
        printf("DEBUG: Sending <%d %s %s>\n",my_msg.cid,my_msg.str1,my_msg.str2); 
                 } 


    rc = sendto(sd, &my_msg, sizeof(my_msg)+1, 0, 
      (struct sockaddr *) &servAddr, 
      sizeof(servAddr)); 
} 
else { 

my_msg.cid = rcv_msg.cid; 
strcpy(my_msg.str1, rcv_msg.str1); 
strcpy(my_msg.str2, rcv_msg.str2); /*my name Nodname contains domain and port number built into C library */ 

    if(atoi(argv[2]) == 1){ 
       printf("DEBUG: Sending <%d %s %s>\n",my_msg.cid,my_msg.str1,my_msg.str2); 
                } 


rc = sendto(sd, &my_msg, sizeof(my_msg)+1, 0, 
     (struct sockaddr *) &servAddr, 
     sizeof(servAddr)); 

        } 

      } 

     return 0; 
     } 

回答

0

您只允许系统读取最多MAX_LEN字节:

rc = recvfrom(sd, &rcv_msg, MAX_LEN, 0, 
    (struct sockaddr *)&servAddr, &servLen 
); 

rcv_msg比两倍大小(它2 * MAX_LEN + sizeof(int))更多。正确的将是:

rc = recvfrom(sd, &rcv_msg, sizeof(rcv_msg), 0, 
    (struct sockaddr *)&servAddr, &servLen 
); 

而且servLen类型必须socklen_t,而不是int;不能保证这两种类型是相同的或可互换的。

而这种代码是错误的,以及:

rc = sendto(sd, &my_msg, sizeof(my_msg)+1, 0, 
    (struct sockaddr *)&servAddr, sizeof(servAddr) 
); 

my_msg正是sizeof(my_msg)大,那么为什么你告诉系统发送sizeof(my_msg)+1字节?那+1在那里做什么?这一个字节超过了结构的结尾,它不属于结构,这个内存可能是填充的,或者已经属于一个不同的变量。你不应该在结构体之后读取那个字节,如果你不走运,这甚至可能会使程序崩溃。

然后你需要注意大小写。在你的代码,命令总是大写(“加入”),但是这行代码比较反对小写的字符串:

if(strcmp(rcv_msg.str1,"join") == 0) { 

strcmp是大小写敏感的,strcmp("JOIN", "join")不会返回0

你是否认为问题可能不是接收方没有正确接收信息,而是发送方没有正确发送信息?我只有你的接收者代码,我没有任何发件人代码。您说客户端在源代码中工作正常,但这并不意味着它可以正常工作,或者按照您认为的方式发送数据。没有看到客户端如何发送数据,我不能真正告诉你问题的确切原因,也没有测试用例来测试服务器代码。

如果我解决了上述所有问题并使服务器向自己发送测试消息,那么在我的系统上工作得很好,您甚至可以直接在线测试该代码,并且它的工作原理也正确,请参见:

http://rextester.com/MSH79937

+0

我试过了,但它仍然没有工作:(。 –

+0

@ MohammedAl-Huneidi然后客户端不发送的样子觉得它的数据。我发现在你的代码两个错误指出但是没有任何客户端代码,我无法构建测试用例和w/o测试用例,我不能告诉你问题出在哪里。 – Mecki

+0

@ MohammedAl-Huneidi还添加了一个测试用例,其中您可以直接在线测试固定代码它只是正常工作,所以如果你仍然有问题,你没有正确添加我指出的所有修复或错误是在客户端。 – Mecki