TCP客户端/服务器打印额外字符串

时间:2013-09-17 08:50:37

标签: c sockets tcp

我正在尝试使用服务器创建程序,并且多个客户端可以通过预定义的端口nummber连接到该服务器。顺便说一句,这是C中的TCP。我在下面有server代码:

服务器代码:

#include <stdio.h>
#include <string.h>    
#include <stdlib.h>    
#include <sys/socket.h>
#include <arpa/inet.h> 
#include <unistd.h>    
#include <pthread.h> 

void *connection_handler(void *);

int main(int argc , char *argv[])
{
    int listenfd , connfd , c , *new_sock;
    struct sockaddr_in servaddr , cliaddr;
    listenfd = socket(PF_INET , SOCK_STREAM , 0);
    if (listenfd == -1)
        puts("SOCKET CREATION ERROR!");
        puts("Socket created");

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(54321);
    bind(listenfd, (struct sockaddr*) &servaddr, sizeof(servaddr) );
    listen(listenfd,2);;
    c = sizeof(struct sockaddr_in);

    while( (connfd = accept(listenfd, (struct sockaddr *)&cliaddr, (socklen_t*)&c)) ){
            puts("Connection accepted");
        pthread_t sniffer_thread;
            new_sock = malloc(1);
            *new_sock = connfd;

            if( pthread_create( &sniffer_thread , NULL ,  connection_handler , (void*) new_sock) < 0)
        {
                perror("Thread Error Connection");
            return 1;
            }
            puts("Handler assigned");
        }

    if (connfd < 0)
    {
            perror("accept failed");
            return 1;
    }
        return 0;
}


void *connection_handler(void *socket_desc)
{
    int sock = *(int*)socket_desc;
    int read_size;
    char client_message[51]="";

    while( (read_size = recv(sock , client_message , 50, 0)) > 0 )
    {
            printf("%s",client_message);
        }

        if(read_size == 0)
        {
            puts("Client disconnected");
            fflush(stdout);
        }
        free(socket_desc);
    return 0;
}

客户代码:

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>



int main(int argc, char **argv)
{
  int sockfd;
  struct sockaddr_in servaddr;
  socklen_t len = sizeof(servaddr);
  char mesg[1024];

  if(argc!=2){ 
      printf("Usage: %s <ip_addr>\n",argv[0]);
      exit(1);
  }

  sockfd = socket(PF_INET,SOCK_STREAM,0);
  bzero(&servaddr, sizeof(servaddr));
  servaddr.sin_family = AF_INET;
  servaddr.sin_port = htons(54321);
  inet_pton(AF_INET,argv[1],&servaddr.sin_addr);
  connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));

  while(1){
    fgets(mesg,sizeof(mesg),stdin);
    sendto(sockfd,mesg,strlen(mesg),0,(const struct sockaddr *)&servaddr,len);
  }
  close(sockfd);
  return 0;
}

我得到以下输出:

Socket created
Connection accepted
Handler assigned
Hello There!
What could be the problem?
I don't know?
the problem?
Hey!
't know?
the problem?

我在客户端终端输入以下字符串:

Hello There!
What could be the problem?
I don't know?
Hey!

问题是当我输入第三个字符串时,输出是第三个字符串,第二个字符串的某些部分仍然出现。可能是什么问题呢?谢谢!

2 个答案:

答案 0 :(得分:2)

  1. TCP是面向流的。

  2. 你不能指望write()写出尽可能多的数据,而且你不能指望read()读取的数据与你告诉它读取的数据一样多

  3. 这两者结合在一起意味着通过套接字传输N个字节时,read()的呼叫数量不一定需要与write()的呼叫数相匹配。

    根据这个结论,读者唯一能够知道的是从它创建的那一刻开始就读到了多少。

    读取器和写入器之间只有两个同步点是连接的创建和关闭。一段时间可以调用会话

    因此,如果想要在一个会话期间传输具有读者未知的不同大小的多个数据块,则需要在会话期间建立其他同步点 ,使读取检测到已收到完整块。

    这样做是为了实现某种协议。

    protcol看起来有多种可能性。协议的详细设计取决于应用程序应涵盖的用例。

    假设只传输文本数据,简单协议可以用\n终止每个数据块。

    作者循环write(),直到发送完所有数据,最后发送\n

    读者在read()周围循环,直到收到\n

答案 1 :(得分:1)

C字符串以空值终止。您没有发送将在您的接收缓冲区中终止字符串的零字节,因此您的printf将打印出它找到的所有字符,直到它达到某个零字节。 strlen以字符数返回字符串的长度,但不计算结尾的零字节。

尝试更改客户端中的行:

sendto(sockfd,mesg,strlen(mesg),0,(const struct sockaddr *)&servaddr,len);

分为:

sendto(sockfd,mesg,1+strlen(mesg),0,(const struct sockaddr *)&servaddr,len);