Unix 通过TCP套接字发送char缓冲区不完整

Unix 通过TCP套接字发送char缓冲区不完整,unix,tcp,sockets,c,Unix,Tcp,Sockets,C,我正在学习如何在C中处理套接字和TCP连接。我有一个应用程序(一个很长的应用程序),它基本上通过系统调用从服务器到客户端发送和接收字符数组,反之亦然(当然是两个独立的C应用程序)。只要我在同一台PC上通过本地连接使用它,在一台终端上运行服务器,在另一台终端上运行客户机,一切正常,数据就会到达目的地。但是,如果我在一台计算机上使用服务器,在另一台计算机上使用客户端,但在同一条internet线路上,向客户端传递一个类似192.168.1.X的地址(取自服务器运行的机器),在建立连接后,我会得到一个

我正在学习如何在C中处理套接字和TCP连接。我有一个应用程序(一个很长的应用程序),它基本上通过系统调用从服务器到客户端发送和接收字符数组,反之亦然(当然是两个独立的C应用程序)。只要我在同一台PC上通过本地连接使用它,在一台终端上运行服务器,在另一台终端上运行客户机,一切正常,数据就会到达目的地。但是,如果我在一台计算机上使用服务器,在另一台计算机上使用客户端,但在同一条internet线路上,向客户端传递一个类似192.168.1.X的地址(取自服务器运行的机器),在建立连接后,我会得到一个错误,告诉我预期的字节数(在发送真正的字符[]之前我通过了它)没有到达。如果我在我的电脑上尝试服务器,在另一台电脑上尝试客户端,在另一个提供商上尝试不同的线路,也是一样的

我遗漏了一些东西,按顺序发送一堆字节有什么限制吗

出现错误的代码

服务器端:

r=htonl(lghstr);
w=write(myFd,&r,sizeof(int));//writes the number of incoming bytes
if(w<0) perror("writeServer4"),exit(-1);
w=write(myFd,tmp->string,lghstr);
if(w<0) perror("writeServer5"),exit(-1);
if(w!=lghstr) perror("ERROR");
r=htonl(lghstr);
w=write(myFd,&r,sizeof(int));//写入传入字节数
if(wstring,lghstr);
如果(w你在一边做了
ntohl()
,而不是在另一边。这可能是用错误的值解释字节

您应该
printf()
两侧的字节,并查看int的计算结果

编辑:我确信这是一个记录在案的编程错误

如果让我猜的话,我会说由于某种原因,你和另一方不同步。你说这运行“大约300次”

尝试向协议中添加一个神奇的整数

下面是一个按此顺序发送的客户机示例

  • 一个始终不变的神奇整数
  • 将要发送的字节长度
  • 要发送的字节数
  • 这使用了分散-聚集机制(它更适合序列化),但除此之外,它有效地做了与客户机相同的事情,只是增加了一个神奇的价值

    当接收器接收到数据时,它可以通过检查输入的幻数来验证数据的顺序是否正确。如果幻数错误,则表示客户端或服务器在流中的位置丢失了自己

    #include <stdio.h>
    #include <stdlib.h>
    #include <stdint.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <sys/types.h>
    #include <sys/uio.h>
    #include <err.h>
    
    #include <time.h>
    
    #define MAGIC 0xDEADBEEFLU
    #define GARBAGE_MAX 65536
    
    const int iterations = 3000;
    
    char * create_garbage_buf(
        void)
    {
      int rc = -1;
      int fd = -1;
      char *buf = NULL;
    
      buf = malloc(GARBAGE_MAX);
      if (!buf)
        err(1, "Cannot allocate buf");
    
      fd = open("/dev/urandom", O_RDONLY);
      if (fd < 0)
        err(1, "Cannot open urandom");
    
      rc = read(fd, buf, GARBAGE_MAX);
      if (rc < 0)
        err(1, "Cannot read from urandom");
      else if (rc != GARBAGE_MAX)
        errx(1, "Expected %d bytes, but got %d reading from urandom",
             GARBAGE_MAX, rc);
    
      close(fd);
      return buf;
    }
    
    int main() {
      int fd, offset, i, rc;
      uint32_t magic = MAGIC;
      uint32_t blen = 0;
      char *buf = NULL;
      struct iovec vecs[3];
    
      /* Seed poor random number generator */
      srand(time(NULL));
    
      /* Use a file for demonstration, but a socket will do just fine */
      fd = open("/dev/null", O_WRONLY);
    
      /* Create some garbage to send */
      buf = create_garbage_buf();
    
      if (fd < 0)
        err(1, "Cannot open file");
    
      /* The first vector, is always the magic */
      vecs[0].iov_len = sizeof(uint32_t);
      vecs[0].iov_base = &magic;
      for (i=0; i < iterations; i++) {
        /* The second vector represents lengh of what we send
         * in this demonstration it is a number between 0 and
         * GARBAGE_MAX/2.
         */
         blen = rand() % (GARBAGE_MAX / 2);
         vecs[1].iov_len = sizeof(uint32_t);
         vecs[1].iov_base = &blen;
         /* The last record is the data to send. Its another random
          * number between 0 and GARBAGE_MAX which represents the offset
          * in our garbage data to send */
         offset = rand() % (GARBAGE_MAX / 2);
         vecs[2].iov_len = blen;
         vecs[2].iov_base = &buf[offset];
    
         rc = writev(fd, vecs, 3);
         if (rc < 0)
           err(1, "Could not write data");
         if (rc != (sizeof(uint32_t)*2 + blen))
           errx(1, "Did not write proper number of bytes to handle");
    
         printf("Wrote %u bytes from offset %u in garbage\n", blen, offset);
      }
    
      free(buf);
      printf("Done!\n");
      return 0;
    }
    
    #包括
    #包括
    #包括
    #包括
    #包括
    #包括
    #包括
    #包括
    #包括
    #定义致命流感的魔力
    #定义垃圾量(最大值65536)
    常数int迭代次数=3000;
    char*创建垃圾(
    (无效)
    {
    int rc=-1;
    int-fd=-1;
    char*buf=NULL;
    buf=malloc(最大垃圾量);
    如果(!buf)
    错误(1,“无法分配buf”);
    fd=开放(“/dev/uradom”,仅限O_rdon);
    如果(fd<0)
    错误(1,“无法打开urandom”);
    rc=读取(fd、buf、垃圾_最大值);
    if(rc<0)
    错误(1,“无法从Uradom读取”);
    else if(rc!=垃圾_MAX)
    errx(1,“预期有%d个字节,但从Uradom读取了%d个”,
    垃圾(最大值,rc);
    关闭(fd);
    返回buf;
    }
    int main(){
    int-fd,偏移量,i,rc;
    uint32_t magic=魔法;
    uint32_t blen=0;
    char*buf=NULL;
    结构iovec-vecs[3];
    /*种子贫乏随机数发生器*/
    srand(时间(空));
    /*使用一个文件进行演示,但是一个套接字就可以了*/
    fd=打开(“/dev/null”,仅限O_wr);
    /*创建一些要发送的垃圾*/
    buf=创建_垃圾_buf();
    如果(fd<0)
    错误(1,“无法打开文件”);
    /*第一个向量,永远是魔法*/
    向量[0].iov_len=sizeof(uint32_t);
    向量[0]。iov_base=&magic;
    对于(i=0;i
    您只在一侧执行
    ntohl()
    。这可能是用错误的值解释字节

    您应该
    printf()
    两侧的字节,并查看int的计算结果

    编辑:我确信这是一个记录在案的编程错误

    如果让我猜的话,我会说由于某种原因,你和另一方不同步。你说这运行“大约300次”

    尝试向协议中添加一个神奇的整数

    下面是一个按此顺序发送的客户机示例

  • 一个始终不变的神奇整数
  • 将要发送的字节长度
  • 要发送的字节数
  • 这使用了分散-聚集机制(它更适合序列化),但除此之外,它有效地做了与客户机相同的事情,只是增加了一个神奇的价值

    当接收器接收到数据时,它可以通过检查输入的幻数来验证数据的顺序是否正确。如果幻数错误,则表示客户端或服务器在流中的位置丢失了自己

    #include <stdio.h>
    #include <stdlib.h>
    #include <stdint.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <sys/types.h>
    #include <sys/uio.h>
    #include <err.h>
    
    #include <time.h>
    
    #define MAGIC 0xDEADBEEFLU
    #define GARBAGE_MAX 65536
    
    const int iterations = 3000;
    
    char * create_garbage_buf(
        void)
    {
      int rc = -1;
      int fd = -1;
      char *buf = NULL;
    
      buf = malloc(GARBAGE_MAX);
      if (!buf)
        err(1, "Cannot allocate buf");
    
      fd = open("/dev/urandom", O_RDONLY);
      if (fd < 0)
        err(1, "Cannot open urandom");
    
      rc = read(fd, buf, GARBAGE_MAX);
      if (rc < 0)
        err(1, "Cannot read from urandom");
      else if (rc != GARBAGE_MAX)
        errx(1, "Expected %d bytes, but got %d reading from urandom",
             GARBAGE_MAX, rc);
    
      close(fd);
      return buf;
    }
    
    int main() {
      int fd, offset, i, rc;
      uint32_t magic = MAGIC;
      uint32_t blen = 0;
      char *buf = NULL;
      struct iovec vecs[3];
    
      /* Seed poor random number generator */
      srand(time(NULL));
    
      /* Use a file for demonstration, but a socket will do just fine */
      fd = open("/dev/null", O_WRONLY);
    
      /* Create some garbage to send */
      buf = create_garbage_buf();
    
      if (fd < 0)
        err(1, "Cannot open file");
    
      /* The first vector, is always the magic */
      vecs[0].iov_len = sizeof(uint32_t);
      vecs[0].iov_base = &magic;
      for (i=0; i < iterations; i++) {
        /* The second vector represents lengh of what we send
         * in this demonstration it is a number between 0 and
         * GARBAGE_MAX/2.
         */
         blen = rand() % (GARBAGE_MAX / 2);
         vecs[1].iov_len = sizeof(uint32_t);
         vecs[1].iov_base = &blen;
         /* The last record is the data to send. Its another random
          * number between 0 and GARBAGE_MAX which represents the offset
          * in our garbage data to send */
         offset = rand() % (GARBAGE_MAX / 2);
         vecs[2].iov_len = blen;
         vecs[2].iov_base = &buf[offset];
    
         rc = writev(fd, vecs, 3);
         if (rc < 0)
           err(1, "Could not write data");
         if (rc != (sizeof(uint32_t)*2 + blen))
           errx(1, "Did not write proper number of bytes to handle");
    
         printf("Wrote %u bytes from offset %u in garbage\n", blen, offset);
      }
    
      free(buf);
      printf("Done!\n");
      return 0;
    }
    
    #包括
    #包括
    #包括
    #包括
    #包括
    #包括
    #包括
    #包括
    #包括
    #定义致命流感的魔力
    #定义垃圾量(最大值65536)
    常数int迭代次数=3000;
    char*创建垃圾(
    (无效)
    {
    int rc=-1;
    int-fd=-1;
    char*buf=NULL;
    buf=malloc(最大垃圾量);
    如果(!buf)
    错误(1,“无法分配buf”);
    fd=开放(“/dev/uradom”,仅限O_rdon);
    
    rC=read(fdc,dest,lghstr);
    ...
    if(rC!=lghstr) perror("error : ")
    
    size_t count = 0;
    while (count < lghstr)
    {
        ssize_t readresult = read(fdc, dest+count, lghstr-count);
        if (readresult == -1)
        {
          // socket error - handle appropriately (typically, just close the connection)
        }
        else if (readresult == 0)
        {
          // The other side closed the connection - handle appropriately (close the connection)
        }
       else
        {
            count += readresult;
        }
    }
    
    rc = recv(fdc, dest, lghstr, MSG_WAITALL);
    if (rc == -1)
    {
      // socket error
    }
    else if (rc == 0)
    {
      // socket closed by remote
    }
    else if (rc < lghstr)
    {
       // the other side likely closed the connection and this is residual data (next recv will return 0)
    }