【问题标题】:read complete data on tcp socket in local network在本地网络中读取 tcp 套接字上的完整数据
【发布时间】:2016-04-03 08:29:05
【问题描述】:

我有一个服务器应用程序和一个客户端应用程序都是用 c 编写的。两者都在 tcp 套接字上进行通信。我想将一大块数据从客户端发送到服务器,也从服务器发送到客户端。

我已经测试了最大 2262 字节。

我发现当我从服务器(运行 debian 7)向客户端(运行 ubuntu 14.04 LTS)发送 2262 个字节时,我能够一次接收所有字节(两者都在通过 wlan 通信的本地网络中)。

但是当我尝试从客户端向服务器发送相同数量的字节时,我只能读取 1448 个字节(通常)和 3000 个字节几次(3000 个字节是我想从文件中读取的最大字节数描述符)一次在服务器上。

我还发现,如果我在同一台机器上同时运行服务器和客户端应用程序,我可以同时从服务器到客户端以及从客户端到服务器发送和接收 2262 字节。在把这个问题放在这里之前,我对所有的案例都进行了多次测试。

我还为此参考了 Beejs 指南,我首先发现我必须确保我一次发送准确的字节数。我用 send 和 write 函数检查了这一点,发现我只一次发送所有字节。

我在那本书中也发现了与 MTU 主题相同的问题。

我的第一个问题是,如果最大传输单位是原因,那么为什么我能够从服务器向客户端发送相同数量的数据,而无法从客户端向服务器接收?

我的第二个问题是,如果不能同时从服务器和客户端发送或接收数据块(绝对小于 10 KB),Beej 建议了一种数据封装的方式。除了 Beej 建议的这种方法之外,还有其他方法可以一次发送和接收数据(最多 10 KB 或可能更多)吗?

客户端代码只是不断地在服务器套接字上写入 2262 字节。 这是服务器代码。

 #include<stdio.h>
 #include<string.h>    //strlen
 #include<stdlib.h>    //strlen
 #include<sys/socket.h>
 #include<arpa/inet.h> //inet_addr
 #include<unistd.h>    //write
 #include<pthread.h> //for threading , link with lpthread

 #define MAX_SIZE 3000 

//the thread function
void *connection_handler(void *);

int main(int argc , char *argv[])
{
int socket_desc , client_sock , c , *new_sock;
struct sockaddr_in server , client;

//Create socket
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
if (socket_desc == -1)
{
    printf("Could not create socket");
}
puts("Socket created");

//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( 6000 );

//Bind
if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
{
    //print the error message
    perror("bind failed. Error");
    return 1;
}
puts("bind done");

//Listen
listen(socket_desc , 3);

//Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);

while( (client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c)) )
{
    puts("Connection accepted");

    pthread_t sniffer_thread;
    new_sock = malloc(1);
    *new_sock = client_sock;

    if( pthread_create( &sniffer_thread , NULL ,  connection_handler , (void*) new_sock) < 0)
    {
        perror("could not create thread");
        return 1;
    }

    //Now join the thread , so that we dont terminate before the thread
    //pthread_join( sniffer_thread , NULL);
    puts("Handler assigned");
}

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

return 0;
}

/*
 * This will handle connection for each client
* */
void *connection_handler(void *socket_desc)
{
//Get the socket descriptor
int sock = *(int*)socket_desc;
int read_size, i;
uint8_t message[MAX_SIZE];

//Receive a message from client
while( (read_size = read(sock , message , sizeof(message))) > 0 )
{
i = 0;
printf("bytes read- %d\n", read_size);

}

if(read_size == 0)
{
    puts("Client disconnected");
    fflush(stdout);
}
else if(read_size == -1)
{
    perror("recv failed");
}

//Free the socket pointer
free(socket_desc);

return 0;
}

【问题讨论】:

  • 您会注意到,无论read 被调用多少次,最终服务器都会接收到客户端发送的所有数据?
  • new_sock = malloc(1); *new_sock = client_sock; 不!这太棒了!你在看哪本书?
  • 是的@Prabhu。你是对的
  • @Seb 这里有什么问题?感谢您的回复。
  • @EdgeGoldberg 问题是,您分配了一个字节,并将该字节视为int(很可能超过一个字节)。我想你打算写类似new_sock = malloc(sizeof *new_sock);... 的东西,学习如何使用 valgrind 可能是个好主意。

标签: c sockets tcp


【解决方案1】:

忘记所有关于 MTU 的事情。 TCP 存在的真正原因是保护您(用户)免受低级 UDP 的影响,包括 MTU。 TCP 是一个面向流 的协议。您在一侧倾倒字节,在另一侧读取字节。大小无关紧要。无论你在一侧倾倒了多少,你永远不会在任何给定时间在接收器一侧拿起多少。使用 TCP 的唯一合理方法是读取流,而不期望通过每个 recv() 调用传递任何特定数量的字节并处理你得到的任何东西。

【讨论】:

    【解决方案2】:

    引用http://linux.die.net/man/2/read

    返回值

    成功时,返回读取的字节数(零表示结束 文件),并且文件位置由这个数字提前。它不是 如果此数字小于请求的字节数,则会出错; 例如,这可能会发生,因为实际上可用的字节更少 现在(可能是因为我们接近文件结尾,或者因为我们 正在从管道或终端读取),或者因为 read() 是 被信号打断

    所以 read 并没有像你期望的那样工作。它不保证它会在一次调用中返回您请求的金额。您指定的数量只是您收到的实际数据的上限。

    【讨论】:

      猜你喜欢
      • 2011-07-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-10
      • 2019-04-02
      • 2016-07-05
      相关资源
      最近更新 更多