【问题标题】:socket send() hangs after sending certain amount of bytes套接字发送()在发送一定数量的字节后挂起
【发布时间】:2017-04-25 03:13:02
【问题描述】:

我想向我的 nodejs TCP 服务器发送一个字符串。

这是我的客户端 (C++) 的代码:

#include <nds.h>
#include <dswifi9.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string>

std::string hostname = "hostname";
int port = 61733;
int sock;

int main(){
    Connect(); //function to connect with a WiFi network
    ConnectToServer();

    unsigned long lastSendTime = 0;
    unsigned long sendInterval = 200; //send a message every 200 milliseconds
    unsigned int nMsgSent = 0;

    while (1){
        unsigned long now = milliseconds(); //function to get the time in milliseconds
        if ((now - lastSendTime) > sendInterval){
            std::string request = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
            request += request;
            request += std::to_string(nMsgSent);
            request += "\n";

            int sendResult = ::send(sock, request.c_str(), request.length(), 0);
            iprintf("req(%d): %d\n", nMsgSent, sendResult);

            nMsgSent++;
            lastSendTime = now;
        }
    }
    return 0;
}

这是我的服务器代码(JS):

var net = require('net');

var tcpServer = net.createServer();  
var tcpPort = 61733;

tcpServer.on('connection', onConnection);

function onConnection(conn){  
  var remoteAddress = conn.remoteAddress + ':' + conn.remotePort;
  console.log('New client connection from: %s', remoteAddress);

  conn.on('data', onData);
  conn.once('close', onClose);
  conn.on('error', onError);

  function onData(data){
    console.log('connection data from %s: %s', remoteAddress, data);
  }

  function onClose(){
    console.log('connection from %s closed', remoteAddress);
  }

  function onError(err){
    console.log('Connection %s error: %s', remoteAddress, err.message);
  }
}

tcpServer.listen(tcpPort, function(){  
  console.log('Server listening on: %j', tcpServer.address());
});

问题来了:

客户端只发送了大约 180 条消息,然后send 挂起。服务器仅接收约 120 条消息。当我增加请求的长度时,客户端发送的请求更少,当我减少长度时,客户端发送的请求更多。我还发现,当我减少 sendInterval 时,我可以在send 挂起之前发送更多请求。我不知道我做错了什么。当我用 nodejs 客户端执行类似的代码时,一切正常,所以问题出在 C++ 客户端。

编辑:

我真的不认为这是必要的,但这里是connectToServer()的代码:

void ConnectToServer()
{
    sock = socket(AF_INET, SOCK_STREAM, 0);
    if (socket >= 0)
    {
        printf("Created Socket!\n");
    }
    else
    {
        printf("Couldn't create socket");
    }

    struct hostent * host = gethostbyname(hostname.c_str());
    if (host != NULL)
    {
        printf("Found IP Address!\n");
    }
    else
    {
        printf("IP not found");
    }   

    struct sockaddr_in server;
    server.sin_family = AF_INET;
    server.sin_port = htons(port);
    server.sin_addr.s_addr = *((unsigned long *)(host->h_addr_list[0]));

    int connectResult = ::connect(sock, (struct sockaddr *)&server, sizeof(server));
    if (connectResult >= 0)
    {
        printf("Connected to server!\n");
    }
    else
    {
        printf("Not connected to server. Err: %d\n", connectResult);
    }   
}

来自 C++ 客户端的输出(发送间隔:2000 毫秒,msgLength:126-127 个字符):

req(1): 126
req(2: 126
req(3): 126
...keeps going on for a while...
req(9): 126
req(10): 126
req(11): 127
req(12): 127
...keeps going on for a while...
req(74): 64
send() hangs after this

nodejs服务器的输出(只接收9条消息):

connection data from ip::port: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ12345678900

...keeps going on for a while...

connection data from ip::port: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ12345678909

测试结果看发送间隔、消息长度和发送消息数量之间是否存在联系:

发送间隔 |消息长度 |消息 -------------------------------------- 200 | 127 | 26 200 | 65 | 33 -------------------------------------- 400 | 65 | 59 400 | 127 | 53 -------------------------------------- 2000 | 65 | 47 2000 | 127 | 21

(我没有看到这些值之间的联系)

【问题讨论】:

  • 不要垃圾标签!这不是 C。C 不是 C++ 不是 C!
  • @Olaf 我知道,但是套接字库是 C 代码,对吧?
  • @user7353781 套接字库的语言与您的问题无关。
  • 如果客户端发送消息的速度快于服务器读取它们的速度,客户端最终会阻塞,直到服务器赶上。您确定服务器正在读取消息吗?
  • 几乎所有你在某个级别使用的库都是如此。你认为应该为每个问题添加C标签吗?

标签: c++ sockets tcp


【解决方案1】:

据我所知,您应该参加一些问题:

  1. 您正试图在客户端的同时发送许多消息 代码,但你没有检查是否有错误,使用 变量sendResult 。在发送另一个之前应该检查它 消息。
  2. 您正在使用同一个线程发送数据并检查具有无限循环发送每条消息的间隔,这会消耗大量 CPU。我建议创建一个线程 (TSync) 来参加 sleepstd::chrono 的间隔,并调用一个通过套接字发送消息的方法,但不在同一个线程中 TSync 因为你会用睡眠阻塞套接字。
  3. 最后,您应该使用FD_SETselect 来检查您何时可以通过套接字发送数据,何时套接字准备好发送更多字节。

可能是您发送消息不受控制的方式会影响 TX 通道,因为它已满因此您应该使用 FD_SETselect 控制输出操作以同步与插座。在写的情况下,Microsoft documentation 说:

select函数用于判断一个或多个socket的状态。对于每个套接字,调用者可以请求有关读取、写入或错误状态的信息。

writefds:可以发送数据。

更新,4 月 21 日:我建议您分享有关您的问题的更多信息,例如服务器的代码和配置,以了解是否存在配置超时或缓冲区大小。您提供的信息还不够,请不要低估我们向您提出的要求,例如以下评论:

我真的不认为这是必要的,但这里是connectToServer()的代码:

连接过程很重要,因为我们可以看到socket服务器是否设置了一些选项。

在这种情况下,您分享给我们的所有信息都可能会有所帮助,而不是认为这不重要。

所以,此时此刻,我能帮到你的就只有这些了。

4 月 24 日更新:尝试以下步骤来控制套接字传输并设置 NON-Blocing 套接字:

  • 连接成功后,在客户端设置socket为NON-BLOCKING。

  • 在循环文件描述符 (FD_SET) 和 select 中使用以检查套接字何时准备好写入。

你的代码应该有如下代码:

void ConnectToServer()
{
    //... your code

    int connectResult = ::connect(sock, (struct sockaddr *)&server, sizeof(server));
    if (connectResult >= 0)
    {
        u_long iMode = 1;
        int iResult = ioctlsocket(sock, FIONBIO, &iMode); //Set the socket Non-Blocking

        printf("Connected to server!\n");
    }
    else
    {
        printf("Not connected to server. Err: %d\n", connectResult);
    }
}

int main(){
    Connect(); //function to connect with a WiFi network
    ConnectToServer();

    unsigned long lastSendTime = 0;
    unsigned long sendInterval = 200; //send a message every 200 milliseconds
    unsigned int nMsgSent = 0;


    fd_set write_fd;

    while (1){
        unsigned long now = milliseconds(); //function to get the time in milliseconds
        if ((now - lastSendTime) > sendInterval){
            std::string request = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
            request += request;
            request += std::to_string(nMsgSent);
            request += "\n";

            FD_ZERO(&write_fd); //Reset the File Descriptor
            FD_SET(sock, &write_fd); //Set se File descriptor to the socket.

            int result = select(max_sd, NULL, &write_fd, NULL, NULL);   //Wait until the socket is ready to write

            if (result < 0)
            {
                iprintf("There was a problem with the sockets reading.\n");
                FD_ZERO(&write_fd);
            }

            int sendResult = ::send(sock, request.c_str(), request.length(), 0);
            iprintf("req(%d): %d\n", nMsgSent, sendResult);

            nMsgSent++;
            lastSendTime = now;
        }
    }
    return 0;
}

【讨论】:

  • 这不起作用:(send() 没有返回任何错误(我记录了send() 的结果,一切似乎都很好)。我不能使用多线程,因为我的目标不支持。我尝试使用FD_SETselect,但这不起作用。
  • @user7353781 你能改变协议吗?如果可以的话,你应该实现一个 ANK 消息来同步每个传输和它的接收。但我不知道你是否可以在你的程序中做到这一点。
  • 不,我想使用 tcp。
  • 我的服务器的代码已经包含在我的问题中,但是问题出在c++客户端,因为nodejs客户端和我的服务器完美配合。
  • @user7353781,添加了一个示例,说明如何在代码中使用非阻塞套接字和select
猜你喜欢
  • 2018-01-07
  • 1970-01-01
  • 2010-11-13
  • 1970-01-01
  • 1970-01-01
  • 2019-11-15
  • 1970-01-01
  • 1970-01-01
  • 2023-03-05
相关资源
最近更新 更多