(TCP)Echo客户端:发送消息后自动断开连接

时间:2014-01-22 20:10:30

标签: linux sockets gcc tcp

所以这是TCP echo客户端的代码。当我让echo服务器侦听端口5000时,客户端连接但是一旦我键入消息并按Enter键,它会自动断开连接。这有什么问题?

源代码(tcp_ec.c):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>



#define MAX_BUFFER 1024

void die(char *s)
{
      perror(s);
      exit(1);
}


int main()

{

  int    connector,flags,r;
  int  port;
  struct hostent*        host;
  struct in_addr         in;
  struct sockaddr_in     rmaddr;
  bool   connected = false;   
  char   sndbuffer[MAX_BUFFER];
  char   rcvbuffer[MAX_BUFFER];
  char   hostname[INET_ADDRSTRLEN];
  char*  exit = "quit";



  if((connector = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))<0){
      perror("socket");
      return -1;
   }


  printf("\n");
  printf("Enter the remote hostname(URL/IP4 address): ");
  scanf("%s", hostname);
  printf("\n");



  printf("Enter the port number you wish to connect(on): ");
  scanf("%u", &port);
  printf("\n");

  if(port==0){
              printf("ERR0R: Port number must be between 1 & 65,535\n");
              printf("\n");
              printf("Enter the port number you wish to connect(on): ");
              scanf("%u", &port);
              printf("\n");        
  }

  host = gethostbyname(hostname);

  if(host==NULL){
         perror("hostname");
         return -1;
  }


  bzero(&rmaddr,sizeof(rmaddr));   
  rmaddr.sin_family = AF_INET;
  rmaddr.sin_port = htons(port);
  bcopy((char*)host->h_addr, (char*)&rmaddr.sin_addr.s_addr, host->h_length);  


  if(connect(connector,(struct sockaddr*)&rmaddr,sizeof(rmaddr))<0){
       perror("connect");
       return -1;
  }else{
       connected=true;
       printf("\n");
       printf("Connected to host: %s",hostname,"on port %u",port);
       printf("     type 'quit' to disconnect\n");
       printf("\n");
  }

  while(connected==true){

       printf(">");
       scanf("%s",sndbuffer);
       printf("\n");

       if(sndbuffer==exit){
           close(connector);
           connected = false;
           return 0;
       }

       if(send(connector,(void*)sndbuffer,sizeof(sndbuffer),MSG_EOR||MSG_NOSIGNAL)<0){
            perror("send");
            close(connector);
            return -1;
       }

       if(recv(connector,(void*)rcvbuffer,sizeof(rcvbuffer),MSG_EOR||MSG_NOSIGNAL)<0){
            perror("recv");
            close(connector);
            return -1;
       }else{
        printf(">>");
            printf("%s\n",rcvbuffer);
            printf("\n");
       }




  }




}

控制台输出(程序输出文件为“tc”):

zermacr0yd@DALEK /usr/lib/gcc/x86_64-linux-gnu/4.7.3/include $ ./tec

Enter the remote hostname(URL/IP4 address): 127.0.0.1

Enter the port number you wish to connect(on): 5000


Connected to host: 127.0.0.1     type 'quit' to disconnect

>asssr

sendmsg: Broken pipe
zermacr0yd@DALEK /usr/lib/gcc/x86_64-linux-gnu/4.7.3/include $ 

当echo_server在端口5000上运行时,这样做。

3 个答案:

答案 0 :(得分:0)

替换:

if(send(connector,(void*)sndbuffer,sizeof(sndbuffer),MSG_EOR||MSG_NOSIGNAL)<0){
... and
if(recv(connector,(void*)rcvbuffer,sizeof(rcvbuffer),MSG_EOR||MSG_NOSIGNAL)<0){

人:

if(send(connector,(void*)sndbuffer,sizeof(sndbuffer),MSG_EOR|MSG_NOSIGNAL)<0){
... and
if(recv(connector,(void*)rcvbuffer,sizeof(rcvbuffer),MSG_EOR|MSG_NOSIGNAL)<0){

...加上一些小错误。

编辑:完整更正的来源

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <netdb.h>
#include <stdbool.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>

#define MAX_BUFFER 1024

void die(char *s)
{
      perror(s);
      exit(1);
}

int main() {
  int    connector,flags,r;
  int  port;
  struct hostent*        host;
  struct in_addr         in;
  struct sockaddr_in     rmaddr;
  bool   connected = false;
  char   sndbuffer[MAX_BUFFER];
  char   rcvbuffer[MAX_BUFFER];
  char   hostname[INET_ADDRSTRLEN];
  char*  exit = "quit";


  if((connector = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))<0){
      perror("socket");
      return -1;
   }

  printf("\n");
  printf("Enter the remote hostname(URL/IP4 address): ");
  scanf("%s", hostname);
  printf("\n");

  printf("Enter the port number you wish to connect(on): ");
  scanf("%u", &port);
  printf("\n");

  if(port==0){
              printf("ERR0R: Port number must be between 1 & 65,535\n");
              printf("\n");
              printf("Enter the port number you wish to connect(on): ");
              scanf("%u", &port);
              printf("\n");
  }
  host = gethostbyname(hostname);

  if(host==NULL){
         perror("hostname");
         return -1;
  }


  bzero(&rmaddr,sizeof(rmaddr));
  rmaddr.sin_family = AF_INET;
  rmaddr.sin_port = htons(port);
  bcopy((char*)host->h_addr, (char*)&rmaddr.sin_addr.s_addr, host->h_length);


  if(connect(connector,(struct sockaddr*)&rmaddr,sizeof(rmaddr))<0){
       perror("connect");
       return -1;
  }else{
       // connected=true;
       printf("\n");
       printf("Connected to host: %son port %u", hostname, port);
       printf("     type 'quit' to disconnect\n");
       printf("\n");
  }

  // while(connected==true){
  while(1){

       printf(">");
       scanf("%s",sndbuffer);
       printf("\n");

       if(sndbuffer==exit){
           close(connector);
           // connected = false;
           return 0;
       }

       if(send(connector,(void*)sndbuffer,sizeof(sndbuffer),MSG_EOR|MSG_NOSIGNAL)<0){
            perror("send");
            close(connector);
            return -1;
       }

       if(recv(connector,(void*)rcvbuffer,sizeof(rcvbuffer),MSG_EOR|MSG_NOSIGNAL)<0){
            perror("recv");
            close(connector);
            return -1;
       }else{
        printf(">>");
            printf("%s\n",rcvbuffer);
            printf("\n");
       }
  }

return 0;
}

输出:

~/src/usenet$ ./a.out

Enter the remote hostname(URL/IP4 address): 127.0.0.1

Enter the port number you wish to connect(on): 7


Connected to host: 127.0.0.1on port 7     type 'quit' to disconnect

>aap

>>aap

>noot

>>noot

>mies

>>mies

>quit

>>quit

>^C

[对“退出”没有反应是由于缺少strncmp()// memcmp(),加上“quit is really”quit \ n“(并且不是nul-terminated)]

答案 1 :(得分:0)

我认为这个问题与Byte Ordering函数有关,因为我注意到添加标题会产生编译器警告。但事实证明,首先是导致问题的原因,以及调用bind的事实( )echo服务器应用程序中的函数给出了一个EONOTSUPP错误,就是套接字没有绑定到特定的地址!它绑定到所有地址,此GCC错误已记录在 Here 。所以现在手头的任务是下载和安装补丁,我会从那里看到它是如何工作的。

答案 2 :(得分:0)

我之前看到,连接()到127.0.0.1上不存在的端口可以成功返回,但它已经存在了几十年,而不是在Linux上。我之后使用的技术是进行零长度写入,如果连接没有真正起作用,则会失败。我从来没有触及它的底部,我已经有20多年没有看到这个问题了。

但你的代码有其他问题。

你忽略'recv()'返回的计数,除非它是否定的。这有两个后果:

  1. 之后你可能会打印垃圾。
  2. 您没有检测到来自recv()的流的结束,因此您不知道对等体何时断开连接,因此您的循环继续并且您发送到已经被对等方关闭的连接,这会产生您的'破管'的问题。在不将结果存储到变量中的情况下调用recv()永远是正确的。
  3. 您还发送垃圾。在这种情况下,你提供给send()的计数应该是'strlen(sndbuffer)'而不是'sizeof sndbuffer',因为你刚刚读了一个带有'fgets()'的以null结尾的字符串。