Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何使用C套接字从客户端到服务器发送和接收整数数组?_C++_Arrays_Sockets_Tcp - Fatal编程技术网

C++ 如何使用C套接字从客户端到服务器发送和接收整数数组?

C++ 如何使用C套接字从客户端到服务器发送和接收整数数组?,c++,arrays,sockets,tcp,C++,Arrays,Sockets,Tcp,问题是:使用TCP和sockets C API从客户机到服务器发送和接收整数数组(稍后是浮点数)。必须同时在Winsock和UNIX中运行 将来可以处理不同的客户端/服务器端,但现在测试是在具有相同端的两台机器(Windows客户端、Linux服务器)之间进行的 我实现了客户机和服务器,这一切似乎都正常工作,但问题在于send()(客户机)和recv()(服务器)调用如何处理我的实现方式。或者,换句话说,如果这种方法有缺陷 方法是: 在客户端上,根据预定义的算法生成uint8_t的向量(N个值序

问题是:使用TCP和sockets C API从客户机到服务器发送和接收整数数组(稍后是浮点数)。必须同时在Winsock和UNIX中运行

将来可以处理不同的客户端/服务器端,但现在测试是在具有相同端的两台机器(Windows客户端、Linux服务器)之间进行的

我实现了客户机和服务器,这一切似乎都正常工作,但问题在于
send()
(客户机)和
recv()
(服务器)调用如何处理我的实现方式。或者,换句话说,如果这种方法有缺陷

方法是:

  • 在客户端上,根据预定义的算法生成uint8_t的向量(N个值序列,从0到254)。此序列将在服务器中复制以进行比较 输入数据(通过比较2个向量)

  • 在客户端上,发送数组大小

  • 在客户端上,使用数组上的循环发送数组,为每个元素调用
    send()

  • 在服务器上,
    recv()
    数组大小

  • 在服务器上,
    recv()

  • 检查我的方法

  • 我将服务器上接收到的字节保存到上一个
    recv()循环中的文件中

  • 循环完成后,读取此文件,根据步骤1)生成另一个大小相同的向量,比较两个向量。 它们匹配,使用测试发送和接收多达255000000个数组元素

  • 问题: 然后可以假设服务器
    recv()
    循环保证与客户端
    send()
    循环匹配

    或者,换句话说,数组索引以相同的顺序到达

    我正在学习优秀的“C语言中的TCP/IP套接字”(Donahoo,Calvert)和echo客户机/服务器示例

    引述:

    “在连接一端调用send()发送的字节不能全部通过在另一端调用recv()返回。”

    recv()
    部分的处理方式有所不同。在本例中,将进行循环,直到接收的字节总数与发送的字节(已知大小)匹配,具体如下:

    while (totalBytesRcvd < echoStringLen)
    {
      bytesRcvd = recv(sock, echoBuffer, RCVBUFSIZE - 1, 0))
      totalBytesRcvd += bytesRcvd;   /* Keep tally of total bytes */
    }
    
    代码:Server.cpp

    if defined(_MSC_VER)
    #include <winsock.h>
    #else
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <errno.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #endif
    
    #include <iostream>
    #include <stdint.h>
    #include <assert.h>
    #include <vector>
    
    const unsigned short server_port = 5000;  // server port
    void server_echo_text();
    void server_recv_data(bool verbose);
    void check_file(const uint32_t arr_size, bool verbose, const size_t slab_size);
    
    ///////////////////////////////////////////////////////////////////////////////////////
    //main
    ///////////////////////////////////////////////////////////////////////////////////////
    
    int main(int argc, char *argv[])
    {
      bool verbose = false;
    
      //no arguments
      if (argc == 1)
      {
        server_recv_data(verbose);
      }
    
      for (int i = 1; i < argc && argv[i][0] == '-'; i++)
      {
        switch (argv[i][1])
        {
        case 'v':
          std::cout << "verbose mode: " << std::endl;
          verbose = true;
          break;
        case 'e':
          std::cout << "running echo server: " << std::endl;
          server_echo_text();
          exit(0);
          break;
        case 'd':
          std::cout << "running data server: " << std::endl;
          server_recv_data(verbose);
          exit(0);
          break;
        }
      }
    
      return 0;
    
    }
    
    ///////////////////////////////////////////////////////////////////////////////////////
    //server_recv_data
    ///////////////////////////////////////////////////////////////////////////////////////
    
    void server_recv_data(bool verbose)
    {
      const int MAXPENDING = 5;             // maximum outstanding connection requests
      int server_socket;                    // socket descriptor for server
      int client_socket;                    // socket descriptor for client
      sockaddr_in server_addr;              // local address
      sockaddr_in client_addr;              // client address
      int  recv_size;                       // size in bytes returned by recv() 
    #if defined (_MSC_VER)
      int len_addr;                         // length of client address data structure
    #else
      socklen_t len_addr;
    #endif
    
      //data
      uint32_t arr_size = 0;
      size_t slab_size = 1;
      FILE *file;
    
    #if defined (_MSC_VER)
      WSADATA ws_data;
      if (WSAStartup(MAKEWORD(2, 0), &ws_data) != 0)
      {
        exit(1);
      }
    #endif
    
      // create socket for incoming connections
      if ((server_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
      {
        exit(1);
      }
    
      // construct local address structure
      memset(&server_addr, 0, sizeof(server_addr));     // zero out structure
      server_addr.sin_family = AF_INET;                 // internet address family
      server_addr.sin_addr.s_addr = htonl(INADDR_ANY);  // any incoming interface
      server_addr.sin_port = htons(server_port);        // local port
    
      // bind to the local address
      if (bind(server_socket, (sockaddr*)&server_addr, sizeof(server_addr)) < 0)
      {
        //bind error: Permission denied
        //You're probably trying to bind a port under 1024. These ports usually require root privileges to be bound.
        std::cout << "bind error: " << strerror(errno) << std::endl;
        exit(1);
      }
    
      // mark the socket so it will listen for incoming connections
      if (listen(server_socket, MAXPENDING) < 0)
      {
        exit(1);
      }
    
      for (;;) // run forever
      {
        // set length of client address structure (in-out parameter)
        len_addr = sizeof(client_addr);
    
        // wait for a client to connect
        if ((client_socket = accept(server_socket, (struct sockaddr *) &client_addr, &len_addr)) < 0)
        {
          exit(1);
        }
    
        // convert IP addresses from a dots-and-number string to a struct in_addr and back
        char *str_ip = inet_ntoa(client_addr.sin_addr);
        std::cout << "handling client " << str_ip << std::endl;
    
        // receive array size
        if ((recv_size = recv(client_socket, (char *)&arr_size, sizeof(uint32_t), 0)) != sizeof(uint32_t))
        {
          exit(1);
        }
    
        std::cout << "server received array size: " << (int)arr_size << std::endl;
    
        //save file
        file = fopen("file.bin", "wb");
        fwrite(&arr_size, sizeof(uint32_t), 1, file);
    
        //receive array
        for (size_t i = 0; i < arr_size; ++i)
        {
          uint8_t v8;
          if ((recv_size = recv(client_socket, (char *)&v8, sizeof(uint8_t), 0)) != sizeof(uint8_t))
          {
            exit(1);
          }
    
          //write 1 element
          fwrite(&v8, sizeof(uint8_t), slab_size, file);
        }
    
        fclose(file);
    
        std::cout << "server received array: " << std::endl;
        check_file(arr_size, verbose, slab_size);
    
        // close client socket
    #if defined (_MSC_VER)
        closesocket(client_socket);
    #else
        close(client_socket);
    #endif
      }
    
    
    }
    
    ///////////////////////////////////////////////////////////////////////////////////////
    //check_file
    ///////////////////////////////////////////////////////////////////////////////////////
    
    void check_file(const uint32_t arr_size, bool verbose, const size_t slab_size)
    {
      //read file
      std::vector<uint8_t> val8(arr_size);
      std::vector<uint8_t> val8_c(arr_size);
      uint32_t arr_size_r;
      uint8_t v8;
      FILE *file;
    
      file = fopen("file.bin", "rb");
      fread(&arr_size_r, sizeof(uint32_t), 1, file);
      assert(arr_size_r == arr_size);
    
      for (size_t i = 0; i < arr_size; ++i)
      {
        fread(&v8, sizeof(uint8_t), slab_size, file);
        val8[i] = v8;
        if (verbose) std::cout << (int)val8[i] << " ";
    
      }
      if (verbose) std::cout << std::endl;
    
      fclose(file);
    
      //check data, define array the same as in client, compare arrays
      v8 = 0;
      for (size_t i = 0; i < arr_size; ++i)
      {
        val8_c[i] = v8;
        v8++;
        if (v8 == 255)
        {
          v8 = 0;
        }
      }
    
      //compare arrays
      for (size_t i = 0; i < arr_size; ++i)
      {
        if (val8_c[i] != val8[i])
        {
          std::cout << "arrays differ at: " << i << " " << (int)val8_c[i] << " " << (int)val8[i] << std::endl;
          assert(0);
        }
      }
    
      std::cout << "arrays match: " << (int)arr_size << " " << (int)arr_size_r << std::endl;
      std::cout << std::endl;
    
    }
    
    如果已定义(\u MSC\u VER)
    #包括
    #否则
    #包括
    #包括
    #包括
    #包括
    #包括
    #包括
    #包括
    #包括
    #包括
    #恩迪夫
    #包括
    #包括
    #包括
    #包括
    const unsigned short server_port=5000;//服务器端口
    void server_echo_text();
    无效服务器记录数据(bool verbose);
    无效检查文件(const uint32 arr_大小、bool verbose、const size_t slab_大小);
    ///////////////////////////////////////////////////////////////////////////////////////
    //主要
    ///////////////////////////////////////////////////////////////////////////////////////
    int main(int argc,char*argv[])
    {
    bool verbose=false;
    //没有争论
    如果(argc==1)
    {
    服务器记录数据(详细);
    }
    对于(int i=1;i
    
    我不确定您是否希望发送单个数字,而不是将它们预先封送到一个大的缓冲区中。您将在性能上获得几个数量级的改进。

    正如@usr所指出的,循环构造得很糟糕。需要的是“全部发送”和“全部接收”函数

    这些都是基于史蒂文斯的书《UNIX网络编程:套接字简介》

    从客户端发送所有函数和发送函数:

    void send_all(int sock, const void *vbuf, size_t size_buf)
    {
      const char *buf = (char*)vbuf;    // can't do pointer arithmetic on void* 
      int send_size;                  // size in bytes sent or -1 on error 
      size_t size_left;               // size left to send 
      const int flags = 0;
    
      size_left = size_buf;
    
      while (size_left > 0)
      {
        if ((send_size = send(sock, buf, size_left, flags)) == -1)
        {
          std::cout << "send error: " << strerror(errno) << std::endl;
          exit(1);
        }
    
        if (send_size == 0)
        {
          std::cout << "all bytes sent " << std::endl;
          break;
        }
    
        size_left -= send_size;
        buf += send_size;
      }
    
      return;
    }
    
     ///////////////////////////////////////////////////////////////////////////////////////
    //client_send_data
    ///////////////////////////////////////////////////////////////////////////////////////
    
    void client_send_data(const char *server_ip, const uint32_t arr_size_mult)
    {
      int sock;                          // socket descriptor
      struct sockaddr_in server_addr;    // server address
    
      //data
      const uint32_t arr_size = arr_size_mult * 255; // array size
    
      //construct array
      std::vector<uint8_t> val8(arr_size);
      uint8_t v8 = 0;
      for (size_t i = 0; i < arr_size; ++i)
      {
        val8[i] = v8;
        v8++;
        if (v8 == 255)
        {
          v8 = 0;
        }
      }
    
    #if defined (_MSC_VER)
          WSADATA ws_data;
          if (WSAStartup(MAKEWORD(2, 0), &ws_data) != 0)
          {
            exit(1);
          }
    #endif
    
      // create a stream socket using TCP
      if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
      {
        exit(1);
      }
    
      // construct the server address structure
      memset(&server_addr, 0, sizeof(server_addr));          // zero out structure
      server_addr.sin_family = AF_INET;                      // internet address family
      server_addr.sin_addr.s_addr = inet_addr(server_ip);    // server IP address
      server_addr.sin_port = htons(server_port);             // server port
    
      // establish the connection to the server
      if (connect(sock, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0)
      {
        std::cout << "connect error: " << strerror(errno) << std::endl;
        exit(1);
      }
    
      //send array size
      send_all(sock, (void *)&arr_size, sizeof(uint32_t));
    
      std::cout << "client sent array size: " << (int)arr_size << std::endl;
    
      //send array
      //std::vector.data() returns the address of the initial element in the container (C++11)
      send_all(sock, (void *)val8.data(), sizeof(uint8_t) * val8.size());
    
      std::cout << "client sent array: " << std::endl;
    
    #if defined (_MSC_VER)
          closesocket(sock);
          WSACleanup();
    #else
          close(sock);
    #endif
    
    }
    
    void send\u all(int sock,const void*vbuf,size\u t size\u buf)
    {
    const char*buf=(char*)vbuf;//无法在void*
    int send_size;//发送的字节大小或错误时为-1
    size\u t size\u left;//要发送的剩余大小
    const int flags=0;
    左尺寸=左尺寸;
    而(左侧尺寸>0)
    {
    如果((发送大小=发送(sock,buf,size\u left,flags))=-1)
    {
    
    std::cout
    std::cout
    闻起来不像
    C
    :)如果您以后考虑使用浮点数(或者更复杂的数据类型组合),您可以考虑使用库将数据结构化为流。Google Protobufs、Cap'n Proto、MAVlink或Apache Thrift可以为您这样做(后两个也在本地支持c)。它们提供了在发送数据之前将数据转换为字节流,并在接收数据之后正确读取数据的有效方法。TCP保证数据将按照在流中发送的顺序发送。但是,对
    send
    recv
    使用单字节缓冲区效率极低。@Andreas Gschossmann.Th这是一个个人项目,主要目标是学习,所以我会尽可能从零开始做每件事,否则就没有乐趣:-)。你是对的,当来到浮动时,这将是一个更大的挑战:-)你假设recv将阅读一条“信息”.TCP不支持消息。该程序将随机失败。
    void send_all(int sock, const void *vbuf, size_t size_buf)
    {
      const char *buf = (char*)vbuf;    // can't do pointer arithmetic on void* 
      int send_size;                  // size in bytes sent or -1 on error 
      size_t size_left;               // size left to send 
      const int flags = 0;
    
      size_left = size_buf;
    
      while (size_left > 0)
      {
        if ((send_size = send(sock, buf, size_left, flags)) == -1)
        {
          std::cout << "send error: " << strerror(errno) << std::endl;
          exit(1);
        }
    
        if (send_size == 0)
        {
          std::cout << "all bytes sent " << std::endl;
          break;
        }
    
        size_left -= send_size;
        buf += send_size;
      }
    
      return;
    }
    
     ///////////////////////////////////////////////////////////////////////////////////////
    //client_send_data
    ///////////////////////////////////////////////////////////////////////////////////////
    
    void client_send_data(const char *server_ip, const uint32_t arr_size_mult)
    {
      int sock;                          // socket descriptor
      struct sockaddr_in server_addr;    // server address
    
      //data
      const uint32_t arr_size = arr_size_mult * 255; // array size
    
      //construct array
      std::vector<uint8_t> val8(arr_size);
      uint8_t v8 = 0;
      for (size_t i = 0; i < arr_size; ++i)
      {
        val8[i] = v8;
        v8++;
        if (v8 == 255)
        {
          v8 = 0;
        }
      }
    
    #if defined (_MSC_VER)
          WSADATA ws_data;
          if (WSAStartup(MAKEWORD(2, 0), &ws_data) != 0)
          {
            exit(1);
          }
    #endif
    
      // create a stream socket using TCP
      if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
      {
        exit(1);
      }
    
      // construct the server address structure
      memset(&server_addr, 0, sizeof(server_addr));          // zero out structure
      server_addr.sin_family = AF_INET;                      // internet address family
      server_addr.sin_addr.s_addr = inet_addr(server_ip);    // server IP address
      server_addr.sin_port = htons(server_port);             // server port
    
      // establish the connection to the server
      if (connect(sock, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0)
      {
        std::cout << "connect error: " << strerror(errno) << std::endl;
        exit(1);
      }
    
      //send array size
      send_all(sock, (void *)&arr_size, sizeof(uint32_t));
    
      std::cout << "client sent array size: " << (int)arr_size << std::endl;
    
      //send array
      //std::vector.data() returns the address of the initial element in the container (C++11)
      send_all(sock, (void *)val8.data(), sizeof(uint8_t) * val8.size());
    
      std::cout << "client sent array: " << std::endl;
    
    #if defined (_MSC_VER)
          closesocket(sock);
          WSACleanup();
    #else
          close(sock);
    #endif
    
    }
    
    void recv_all(int sock, void *vbuf, size_t size_buf, FILE *file)
    {
      char *buf = (char*)vbuf;  // can't do pointer arithmetic on void* 
      int recv_size;            // size in bytes received or -1 on error 
      size_t size_left;         // size left to send 
      const int flags = 0;
    
      size_left = size_buf;
    
      while (size_left > 0)
      {
        if ((recv_size = recv(sock, buf, size_left, flags)) == -1)
        {
          std::cout << "recv error: " << strerror(errno) << std::endl;
          exit(1);
        }
    
        if (recv_size == 0)
        {
          std::cout << "all bytes received " << std::endl;
          break;
        }
    
        //save to local file
        fwrite(buf, recv_size, 1, file);
    
        size_left -= recv_size;
        buf += recv_size;
      }
    
      return;
    }
    
    ///////////////////////////////////////////////////////////////////////////////////////
    //server_recv_data
    ///////////////////////////////////////////////////////////////////////////////////////
    
    void server_recv_data(bool verbose)
    {
      const int MAXPENDING = 5;             // maximum outstanding connection requests
      int server_socket;                    // socket descriptor for server
      int client_socket;                    // socket descriptor for client
      sockaddr_in server_addr;              // local address
      sockaddr_in client_addr;              // client address
    #if defined (_MSC_VER)
          int len_addr;                         // length of client address data structure
    #else
          socklen_t len_addr;
    #endif
    
      //data
      uint32_t arr_size = 0;
      const size_t slab_size = 1;
      FILE *file;
    
    #if defined (_MSC_VER)
          WSADATA ws_data;
          if (WSAStartup(MAKEWORD(2, 0), &ws_data) != 0)
          {
            exit(1);
          }
    #endif
    
      // create socket for incoming connections
      if ((server_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
      {
        exit(1);
      }
    
      // construct local address structure
      memset(&server_addr, 0, sizeof(server_addr));     // zero out structure
      server_addr.sin_family = AF_INET;                 // internet address family
      server_addr.sin_addr.s_addr = htonl(INADDR_ANY);  // any incoming interface
      server_addr.sin_port = htons(server_port);        // local port
    
      // bind to the local address
      if (bind(server_socket, (sockaddr*)&server_addr, sizeof(server_addr)) < 0)
      {
        //bind error: Permission denied
        //You're probably trying to bind a port under 1024. These ports usually require root privileges to be bound.
        std::cout << "bind error: " << strerror(errno) << std::endl;
        exit(1);
      }
    
      // mark the socket so it will listen for incoming connections
      if (listen(server_socket, MAXPENDING) < 0)
      {
        exit(1);
      }
    
      for (;;) // run forever
      {
        // set length of client address structure (in-out parameter)
        len_addr = sizeof(client_addr);
    
        // wait for a client to connect
        if ((client_socket = accept(server_socket, (struct sockaddr *) &client_addr, &len_addr)) < 0)
        {
          exit(1);
        }
    
        // convert IP addresses from a dots-and-number string to a struct in_addr and back
        char *str_ip = inet_ntoa(client_addr.sin_addr);
        std::cout << "handling client " << str_ip << std::endl;
    
        ///////////////////////////////////////////////////////////////////////////////////////
        //receive data and save to local file as received
        ///////////////////////////////////////////////////////////////////////////////////////
    
        //save local file
        file = fopen(check_file_name.c_str(), "wb");
    
        //receive/save array size
        recv_all(client_socket, &arr_size, sizeof(uint32_t), file);
    
        std::cout << "server received array size: " << (int)arr_size << std::endl;
    
        //receive/save array
        uint8_t *buf = new uint8_t[arr_size];
    
        recv_all(client_socket, buf, sizeof(uint8_t) * arr_size, file);
    
        delete[] buf;
    
        fclose(file);
    
        std::cout << "server received array: " << std::endl;
    
        //check
        check_file(arr_size, verbose, slab_size);
    
        // close client socket
    #if defined (_MSC_VER)
            closesocket(client_socket);
    #else
            close(client_socket);
    #endif
      }
    
    
    }