1

我正在尝试使用服务器制作程序,并且多个客户端可以通过预定义的端口号连接到该服务器。顺便说一句,这是 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!

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

4

2 回答 2

2
  1. TCP是面向流的。

  2. 你不能指望它write()写的数据和你告诉它写的一样多,你也不能指望它read()读的数据和你告诉它读的数据一样多。

这两者放在一起意味着要通过套接字传输 N 个字节,调用次数read()不一定需要与调用次数相匹配write()

根据这个结论,读者唯一能知道的是它从创建的那一刻起阅读了多少。

读写器之间仅有的两个同步点是连接的创建和关闭。期间可以称为会话

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

这样做是在实现某种协议。

协议的外观有无穷无尽的可能性。协议的详细设计取决于应用程序应涵盖的用例。

假设只传输文本数据,一个简单的协议可能是用\n.

writer 循环,write()直到所有数据都发送完毕,最后发送一个\n.

阅读器循环,read()直到\n收到 a 。

于 2013-09-17T09:22:05.147 回答
1

C 字符串以 null 结尾。您不会发送零字节来终止接收缓冲区中的字符串,因此您的 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);
于 2013-09-17T08:55:14.273 回答