两个write()(它们之间有sleep())到socket

时间:2016-03-25 11:39:59

标签: c sockets unix

我正在练习echo服务器/客户端,并且遇到了一些问题。

这是头文件名myheader.h

  #include <arpa/inet.h>
  #include <string.h>
  #include <stdlib.h>
  #include <unistd.h>
  #include <errno.h>
  #include <stdio.h>
  #include <signal.h>

  typedef void Sigfunc(int);

  static int read_cnt;
  static char *read_ptr;
 static char read_buf[1024];

 ssize_t
 readn(int fd, void *vptr, size_t n)
 {
          size_t nleft;
         ssize_t nread;
         char *ptr;

          ptr=vptr;
          nleft=n;

          while(nleft>0)
          {
                  if((nread=read(fd, ptr, nleft))<0)
                  {
                          if(errno==EINTR)
                                  nread=0;
                          else
                                  return -1;
                  }
                  else if(nread==0)
                          break;          /* End of File reached */

                  nleft-=nread;
                  ptr+=nread;
          }
          return (n-nleft);
  }

  ssize_t
  writen(int fd, const void *vptr, size_t n)
  {
          size_t nleft;
          ssize_t nwritten;
          const char *ptr;

          ptr=vptr;
          nleft=n;

          while(nleft>0)
          {
                  if((nwritten=write(fd, ptr, nleft))<=0)
                  {
                          if(nwritten<0 && errno==EINTR)
                                  nwritten=0;     /* and call write() again */
                          else
                                  return -1;      /* error */
                  }

                  nleft-=nwritten;
                  ptr+=nwritten;
          }

          return n;
  }

  static ssize_t
  my_read(int fd, char *ptr)
  {
          if(read_cnt<=0)
          {
                  again:
                          if((read_cnt=read(fd, read_buf, sizeof(read_buf)))<0)
                          {
                                  if(errno==EINTR)
                                          goto again;
                                  return -1;
                          }
                          else if(read_cnt==0)
                                  return 0;
                          read_ptr=read_buf;
          }

          read_cnt--;

          *ptr=*read_ptr++;
          return 1;
  }

  ssize_t
  Readline(int fd, void *vptr, size_t maxlen)
  {
          ssize_t n, rc;
          char    c, *ptr;
          ptr=vptr;

         for(n=1; n<maxlen; n++)
         {
                 if((rc=my_read(fd, &c))==1)
                 {
                         *ptr++=c;
                         if(c=='\n')
                                 break;
                 }
                 else if(rc==0)
                 {
                         *ptr=0;
                         return (n-1);
                 }
                 else
                         return -1;
         }

         *ptr=0;
         return n;
 }

 void
 str_echo(int sockfd)
 {
         ssize_t n;

         char    buf[1024];

         again:
                 while((n=read(sockfd, buf, 1024))>0)
                         writen(sockfd, buf, n);

                 if(n<0 && errno==EINTR)
                         goto again;
                 else if(n<0)
                 {
                         printf("str_echo: read error");
                         exit(1);
                 }
 }

 void
 str_cli(FILE *fp, int sockfd)
 {
         char    sendline[1024], recvline[1024];

         while(fgets(sendline, 1024, fp)!=NULL)
         {
                 //writen(sockfd, sendline, strlen(sendline));

                 writen(sockfd, sendline, 1);
                 sleep(1000);
                 writen(sockfd, sendline+1, strlen(sendline)-1);
                 if(Readline(sockfd, recvline, 1024)==0)
                 {
                         printf("str_cli: server terminated prematurely");
                 }

                 fputs(recvline, stdout);
         }
 }


 Sigfunc*
 Signal(int signo, Sigfunc *func)
 {
         struct sigaction act, oact;

         act.sa_handler=func;
         sigemptyset(&act.sa_mask);
         act.sa_flags=0;

         if(signo==SIGALRM)
         {
 #ifdef SA_INTERRUPT
                 act.sa_flags |=SA_INTERRUPT;
 #endif
         }
         else
         {
 #ifdef SA_RESTART
                 act.sa_flags |=SA_RESTART;
 #endif
         }

         if(sigaction(signo, &act, &oact)<0)
                 return SIG_ERR;

         return oact.sa_handler;
 }

这是echo客户端源代码:

       #include "myheader.h"
       #include <sys/socket.h>
       #include <netinet/in.h>

       int
       main(int argc, char** argv)
       {
               struct sockaddr_in servaddr;
               int sockfd;

              sockfd=socket(AF_INET,SOCK_STREAM, 0);

              bzero(&servaddr, sizeof(servaddr));

              servaddr.sin_family=AF_INET;
              servaddr.sin_port=htons(9877);
              inet_pton(AF_INET, argv[1], &servaddr.sin_addr);

              connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr));

              str_cli(stdin, sockfd);

              exit(0);
      }

这是echo服务器代码:

   #include "myheader.h"
   #include <signal.h>

   void
   sig_chld(int signo)
   {
           pid_t   pid;
           int     status;

          while((pid=waitpid(-1, &status, WNOHANG))>0)
                  printf("child %d terminated\n", pid);

          return;
  }

  int
  main(int argc, char** argv)
  {
          int     listenfd, connfd;
          pid_t   childpid;
          socklen_t       clilen;
          struct sockaddr_in cliaddr, servaddr;

          listenfd=socket(AF_INET, SOCK_STREAM, 0);

          bzero(&servaddr, sizeof(servaddr));

          servaddr.sin_family=AF_INET;
          servaddr.sin_port=htons(9877);
          servaddr.sin_addr.s_addr=htonl(INADDR_ANY);

          bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr));

          listen(listenfd, 5);

          signal(SIGCHLD, sig_chld);

          for(;;)
          {
                  clilen=sizeof(cliaddr);
                  if((connfd=accept(listenfd, (struct sockaddr*)&cliaddr, &clilen))<0)
                  {
                          if(errno=EINTR)
                                  continue;
                          else
                          {
                                  printf("accpet error\n");
                                  exit(1);
                          }
                  }

                  if((childpid=fork())==0)
                  {
                          close(listenfd);
                          str_echo(connfd);
                          exit(0);
                  }
                  close(connfd);
          }
  }

所以当我连接到echo服务器时,我输入的消息就像&#39; hello guys&#39; 然后,它应该首先将数据发送到服务器1字节,这里是h

然后它睡了10秒钟。然后应发送ello guys

但是,当我输入“你好”的时候。我得到了'你好'的家伙&#39;从服务器立即。为什么我立即得到完整的消息,而不是分开?

这是我收到的TCPDUMP :(我发送hello

21:17:27.798745 IP localhost.47761 > localhost.9877: Flags [S], seq 319562030, win 43690, options [mss 65495,sackOK,TS val 1147465 ecr 0,nop,wscale 10], length 0
21:17:27.798762 IP localhost.9877 > localhost.47761: Flags [S.], seq 3488701479, ack 319562031, win 43690, options [mss 65495,sackOK,TS val 1147465 ecr 1147465,nop,wscale 10], length 0
21:17:27.798779 IP localhost.47761 > localhost.9877: Flags [.], ack 1, win 43, options [nop,nop,TS val 1147465 ecr 1147465], length 0
21:17:58.130012 IP localhost.47761 > localhost.9877: Flags [P.], seq 1:7, ack 1, win 43, options [nop,nop,TS val 1155048 ecr 1147465], length 6
21:17:58.130065 IP localhost.9877 > localhost.47761: Flags [.], ack 7, win 43, options [nop,nop,TS val 1155048 ecr 1155048], length 0
21:17:58.130093 IP localhost.9877 > localhost.47761: Flags [P.], seq 1:7, ack 7, win 43, options [nop,nop,TS val 1155048 ecr 1155048], length 6
21:17:58.130114 IP localhost.47761 > localhost.9877: Flags [.], ack 7, win 43, options [nop,nop,TS val 1155048 ecr 1155048], length 0

0 个答案:

没有答案