Java -> C++ TCP 套接字直到关闭才发送

Java -> C++ TCP Socket does not send until close

本文关键字:套接字 gt TCP C++ Java      更新时间:2023-10-16

我遇到了另一个TCP套接字问题。我已经阅读了一大堆问题和类似问题的答案,但我的问题在某种程度上有所不同。

我有一个 Java 客户端和C++服务器。一切都按预期进行,直到我使用不同的机器(到目前为止等于其他问题(来自客户端的消息似乎卡在 den TCP 缓冲区中。当我最终关闭套接字时,所有内容都发送到服务器。但是这些单条消息是控制消息,所以我需要立即发送它们。据我所知,这是预期的行为,但我如何发送可靠的控制消息。

有没有办法强制发送消息。 (我可以让套接字打开几分钟,什么都不发送。

有什么问题吗?(请参阅以下代码(

我是否必须每次关闭套接字才能执行真正的刷新?

我应该改用 UDP 并增加协议工作吗?

Javacode:

mSocketSend = new Socket();
mSocketSend.connect(new InetSocketAddress(mServerIp, mSocketPortSend), mTimeOut);
PrintWriter pw = new PrintWriter(mSocketSend.getOutputStream(), true);
pw.println(data);

C++代码:

   opening socket...(i leave that)
   char* buffer = new char[1024];
   int rc = recv(mConnectedSocket, buf, 1024, 0);

如果你想要更多。写吧。我几乎把所有东西都省略了。^^ 我认为这无关紧要。沟通通常很好。完全没有错误。所以它只是这个TCPBuffer的东西。

我知道应该有一些分隔符或消息长度的东西。但实际上:未发送的消息长度无济于事。^^

感谢您的帮助。

编辑 #01 整堆代码:

mSocket->createSocketServer(22);
    char* buffer = new char[1024];
 while(true){
        int numberBytes = mSocket->receiveChars(buffer, 1024);
        if (numberBytes > 0){
            uninterestingHandlingFunction(buffer);
        }else{
            mSocket->createSocketServer(22);
        }
    }
bool Socket::createSocketServer(u_short port)
{
    if (mConnectedSocket != INVALID_SOCKET)
    {
        closesocket(mConnectedSocket);
    }
    if (s == INVALID_SOCKET)
    {
        WSADATA wsa;
        if (WSAStartup(MAKEWORD(2,0), &wsa) != 0)
            return 0;
        s = socket(AF_INET, SOCK_STREAM, 0);
        if (s == INVALID_SOCKET)
            return 0;
        SOCKADDR_IN addr;
        memset(&addr, 0, sizeof(SOCKADDR_IN));
        addr.sin_family=AF_INET;
        addr.sin_port=htons(port);
        addr.sin_addr.s_addr=ADDR_ANY;
        if (bind(s, (SOCKADDR*)&addr, sizeof(SOCKADDR_IN)) == SOCKET_ERROR)
        {
            s = INVALID_SOCKET;
        } else if (listen(s, 10) == SOCKET_ERROR)
        {
            s = INVALID_SOCKET;
        }
        if (s == INVALID_SOCKET)
        {
            closesocket(s);
            return 0;
        }
    }
    mConnectedSocket = accept(s, NULL, NULL);
    if (mConnectedSocket == INVALID_SOCKET)
    {
        closesocket(s);
        return 0;
    }
    return 1;
}
int Socket::receiveChars(char* buf, unsigned maxSize)
{
    if (mConnectedSocket == INVALID_SOCKET)
        return -1;
    int rc = recv(mConnectedSocket, buf, maxSize, 0);
    if (rc == SOCKET_ERROR)
    {
        std::cout << "Socket: error " << WSAGetLastError() << std::endl;
    }
    return rc;
}

你想要它...

编辑#2再试一次

我尝试过的东西很少。起初:每次通过真实网络连接的设备上都不会发生此问题。-> 完全重新启动客户端和服务器 ->问题未发生 -> 完全重新启动客户端和服务器 -出现>问题

可悲的是,我不知道从这个习惯中得到什么。

我偶然发现的另一件事是绑定和侦听套接字(在代码套接字中(。此套接字侦听连接,如果工作线程需要新连接(在启动时或如果上一个关闭(,套接字 s 会向 mConnectedSocket 提供下一个排队连接以进行 recv,则在处理一个连接时,其他连接将积压。从 Java 视图:已连接套接字(设备 A(。下一个套接字(设备 B(尝试连接。-> 连接成功(如果确实发生这种情况,则在代码中正确控制( ->然后以自然物质发送数据。(套接字仍在 c++ 端的积压工作中(

嗯,这很难转化为我所经历的习惯。我会试着表达我的想法。Javaside:PrintWriter 被创建。馈送数据并刷新。因为连接未完全建立(C++端没有其他连接的套接字(。刷新不起作用。在关闭时,套接字最终刷新其内容。

如果你这么认为,请告诉我闭嘴。我真的不知道"连接积压"在实现中实际上意味着什么"^^

我知道,我应该为每个连接打开一个新线程,但目前我不能。所以坚持使用这个服务器代码。

你需要做一个 flush((,将数据推出去。

PrintWriter.flush();

或者使用具有自动刷新功能的编写器。

您还应该确保服务器读取一行(直到(而不是完整的1024个字符,但我不知道recv((是做什么的,所以我不知道。

修复了它。有点尴尬...我在编辑中注意到积压确实是问题所在。如果一次有两个客户端连接到服务器,则第二个客户端将积压,当第一个客户端断开连接时,将处理他的消息。

另外(这是线索(

如前所述,它是一个安卓Java客户端。Java 端还有另一个线程用于从C++服务器接收数据。此套接字连接到另一个端口。但是我在设置活动中设置了要连接的端口和 IP 地址,并且另一个套接字的端口错误作为默认值(与问题套接字相同,采用了错误的变量(因此,此套接字首先连接,问题套接字连接到积压工作。仅当我输入设置以设置另一个 IPAddress 时(例如,当我连接到远程主机而不是本地主机时(,才会使用此默认值

不可思议的情况...我什至没有写设置...

WIRESHARK会解决这个问题。

PrintWriter pw = new PrintWriter(mSocketSend.getOutputStream(), true);
pw.println(data);
pw.flush();

实际上你的问题可能在接收端,你的recv需要循环(你可以谷歌搜索这个的例子(。不能保证每次打电话给recv不会得到多少。如果您知道您正在刷新 Java 站点上的数据,那可能是您的问题。

当您使用自动刷新甚至尝试使用显式flush()时:

可能是因为你没有打开输入流。也尝试做一个getInputStream()

否则,您是否尝试过:

  1. 您不使用connect而只是直接在Socket构造函数中给出参数的任何差异?

  2. setTcpNoDelay在插座上(不过不应该导致几分钟的延迟!!(?

您的循环编码不正确。每个新的 recv(( 都会覆盖前一个。您应该前进偏移参数。