2012-01-28 66 views
0

更新:根据建议更新src。 strcat a \ n \ 0到命令并改变sizeof。客户端发送“成功”,但服务器从未“成功”接收。BSD套接字不工作

我已经投入了大量的努力,试图让一个普通的旧的TCP套接字工作。我基本上有一个简单的客户端和服务器设置。目前我在我的服务器上没有收到任何东西,我的客户端上只有4个字节(本例中为“GOTY”)。

RECEIVED (null) 

客户端输出仅数个街区,并从未停止:在

服务器输出输出这和移动。如果我杀了服务器我得到这个输出

Connect success 
Received Response: 

服务器

int Server::update(char *getbuf) 
{ 
    int ready = poll(pollfds, 1, 100); 

    if (ready == -1) 
    { 
     logger.info("Poll failed"); 
     return FALSE; 
    } 

    if (pollfds[0].revents & POLLIN) 
    {  
     ssize_t z; 

     logger.info("Connection available"); 

     struct sockaddr_in client_address; 
     memset(&client_address, 0, sizeof client_address); 
     socklen_t alen = sizeof(client_address); 

     // ACCEPT 
     clientsocket = accept(serversocket, (struct sockaddr *)&client_address, &alen); 
     if(!clientsocket) 
      logger.fail("Accept Fail"); 

     // READ 
     z = recv(clientsocket, getbuf, 512, MSG_WAITALL); 
     if (z < 0) 
      fprintf(stderr,"receive failure\n"); 
     else 
      fprintf(stderr,"receive succeed\n"); 

     getbuf[z] = 0; 

     respond(getbuf); 

     //closeConnection(); 

     logger.data("RECEIVED %s", getbuf); 

     getbuf[z] = 0; 

     return TRUE; 
    } 

    return FALSE; 
} 

void Server::respond(char *response) 
{ 
    // SEND 
    ssize_t z; 

    z = send(clientsocket, response, strlen(response), 0); 
    if (z < 0) 
     fprintf(stderr,"send failure\n"); 
    else 
     fprintf(stderr,"send succeed\n"); 
} 

CLIENT

我增加了客户端代码。我现在使用strlen,但它似乎没有帮助的东西。

int main(int argc, char **argv) 
{ 
    int abort = 0; 
    int port; 
    in_addr_t address; 
    char *command; 

    ssize_t z; 
    int com_socket; 
    struct sockaddr_in server_address; 
    struct timeval timeout; 

    int opt; 
    int val = 0; 
    char getbuf[512]; 

    //Defaults 
    address = inet_addr("127.0.0.1"); 
    port = 4949; 

    //INCLUDED ARGUMENTS FROM CLI 
    while((opt = getopt(argc, argv, "a:p:c:")) > 0) 
    { 
     switch(opt) 
     { 
      case 'a': 
       address = inet_addr(optarg); 
       break; 
      case 'p': 
       port = atoi(optarg); 
       break; 
      case 'c': 
       abort = 1; 
       command = (char *)optarg; 
       break; 
      default: 
       fprintf(stderr, "-a IPADDRESS -p PORT -c COMMAND\n",argv[0]); 
     } 
    } 

    // Server 
    memset(&server_address, 0, sizeof(server_address)); 
    server_address.sin_family = AF_INET; 
    server_address.sin_port = htons(port); 
    server_address.sin_addr.s_addr = address; 

    if (server_address.sin_addr.s_addr == INADDR_NONE) 
     fprintf(stderr, "Server address failed\n"); 

    if(!abort) 
    { 
     fprintf(stderr, "No Command given\n"); 
     fprintf(stderr, "-a IPADDRESS -p PORT -C COMMAND\n"); 
     exit(0); 
    } 
    else 
    { 
     fprintf(stderr, "Address %s Port %d Command %s\n", inet_ntoa(server_address.sin_addr), port, command); 
    } 

    // Create com_socket 
    com_socket = socket(PF_INET, SOCK_STREAM, 0); 
    if (com_socket == -1) 
     fprintf(stderr, "Socket failed\n"); 

    /* 
    // Client 
    struct sockaddr_in client_address; 
    memset(&client_address,0,sizeof client_address); 
    client_address.sin_family = AF_INET; 
    client_address.sin_port = 0; 
    client_address.sin_addr.s_addr = ntohl(INADDR_ANY); 

    if (client_address.sin_addr.s_addr == INADDR_NONE) 
     fprintf(stderr, "Client address failed\n"); 

    // Bind 
    z= bind(com_socket, (struct sockaddr *)&client_address, sizeof (client_address)); 
    if (z == -1) 
     fprintf(stderr,"Binding port\n"); 
    */ 

    timeout.tv_sec = 2; /* 2 seconds */ 
    timeout.tv_usec = 0; /* + 0 usec */ 

    socklen_t addrlen = sizeof(struct sockaddr_in); 

    // Connect 
    //z = connectWithTimeout(com_socket, (struct sockaddr *) &server_address, len_inet, &timeout); 
    z = connect(com_socket, (struct sockaddr *) &server_address, sizeof(server_address)); 
    if(z == -1) 
    { 
     if(errno == EINPROGRESS) 
     { 
      fprintf(stderr, "EINPROGRESS non block start\n"); 
     } 

     if(errno == EALREADY) 
     { 
      fprintf(stderr, "EALREADY non block subsequent request\n"); 
     } 

     fprintf(stderr, "Connect failed\n"); 
    } 
    else 
     fprintf(stderr, "Connect success\n"); 

    strcat(command, "\n\0"); 

    // SEND 
    z = send(com_socket, command, strlen(command)+2, 0); 
    if (z < 0) 
     fprintf(stderr,"send failure\n"); 
    else 
     fprintf(stderr,"send succeed\n"); 

    // READ 
    z = recv(com_socket, getbuf, 512, MSG_WAITALL); 
    if (z < 0) 
     fprintf(stderr,"receive failure\n"); 
    else 
     fprintf(stderr,"receive succeed\n"); 

    // Output 
    fprintf(stderr, "Received Response: %s\n", getbuf); 

    close(com_socket); 

    exit(1); 
} 

我只是不知道为什么这是行不通的。我一遍又一遍地结束了。

这是一个嵌入式Linux系统。

+1

您没有显示实际调用'send()'的函数。我建议在'strace'下运行你的服务器和客户端来查看它实际传递给'send()'的数据和长度。 – mark4o 2012-01-28 07:56:08

+0

您是否尝试使用众多工具(特别是'gcc -Wall -g','gdb','valgrind','strace' ...)来使您的代码在常规Linux桌面上工作? – 2012-01-28 08:33:17

回答

-2

套接字上的发送操作通常会被缓存,因此您的响应函数可能无法清除所有数据。在respond()末尾尝试刷新操作以获取额外数据。

在我看来,你看到阻塞行为,你可能想看看阻塞/非阻塞如何影响套接字。

+2

套接字不被缓冲;没有冲洗功能。 – 2012-01-28 06:27:22

+0

啊。我只使用套接字库(如python asyncore,luasocket等),所以我想他们添加自己的缓冲区。我一直认为它是由os完成的。 – SpliFF 2012-01-28 10:17:23

2

既然你还没有真正分享你的“响应”函数的源代码,我的精神力量告诉我,它看起来是这样的:

void Server::respond(char* str) 
{ 
    send(clientsock, str, sizeof(str), 0); 
} 

因此,“的sizeof(STR)”正在评估,以4因为这是你机器上指针的大小。这与客户端收到“GOTY”(您打算发送的消息的前4个字节)一致。

将其更改为以下:

void Server::respond(char* str) 
{ 
    send(clientsock, str, strlen(str), 0); 
} 

而且,你永远不应该认为是发送和recv将返回等于数据您预期发送或接收量的值。因此,你应该循环发送/ recv的非阻塞调用,直到整个消息已被发送或消耗。

+0

您如何知道消息何时完成? – napierzaza 2012-01-29 15:02:36

+0

你不知道。您必须将传入的字符保存在缓冲区中并等待发生'\ n'。 (或其他一些协议定义的语句终结符) – wildplasser 2012-01-29 16:06:53

+0

我已经用我的信息更新了我的帖子。 – napierzaza 2012-01-29 18:59:36

4

在服务器中:这显然是错误的。 strlen()返回在之前的缓冲区中read()/ recv()的字符串的长度。

// READ 
    z = recv(clientsocket, getbuf, strlen(getbuf), MSG_WAITALL); 
    if (z < 0) 
     fprintf(stderr,"receive failure\n"); 

此外:在respond()中,strlen()假定响应“string”是空的。不是这样。

z = send(clientsocket, response, strlen(response), 0); 

并且客户端代码中出现相同类型的错误。

更新:由于OP不知道如何生活没有字符串函数,我会说明如何做到这一点。

... snipped ... 
// READ 
    z = recv(clientsocket, getbuf, 512, MSG_WAITALL); 
    if (z < 0) { 
     // .... if (errno == EAGAIN) continue; 
     fprintf(stderr,"receive failure %d(%s) \n" 
      , errno, strerror(errno)); 
     break; } 

    fprintf(stderr,"receive succeed\n"); 

    respond(getbuf, z); 

    return TRUE; 
    } 
return FALSE; 
} 

void respond(char *response, size_t siz) 
{ 
// SEND 
size_t done; 
ssize_t z; 

for (done = 0; done < siz; done += z) { 
    z = send(clientsocket, response+done, siz-done, 0); 
    if (z < 0) { 
     if (errno == EAGAIN) continue; 
     fprintf(stderr,"send failure %d(%s)\n" 
      , errno, strerror(errno)); 
     break; } 
    fprintf(stderr,"send succeed\n"); 
    } 
} 
+0

那么我该如何知道我接受的时间长短呢?如果我把缓冲区的大小,它会挂起,直到它收到256字节? – napierzaza 2012-01-29 18:18:11

+0

不会。它会读取尽可能多的字节。你的程序应该记住它已经收集了多少数据,以及缓冲区剩下多少空间。 – wildplasser 2012-01-29 18:21:13

+0

所以你确认在这种情况下我应该把缓冲区的大小?因为它看起来好像仍然挂在接收上,其值为256(缓冲区大小)。 – napierzaza 2012-01-29 18:35:51