0

我面临另一个 TCP 套接字问题。我已经阅读了大量问题以及类似问题的答案,但我的问题在某种程度上有所不同。

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

有没有办法强制发送消息。(我可以让套接字打开几分钟而不发送任何内容。)

有什么不对?(见以下代码)

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

我是否应该使用 UDP 来替代协议工作量?

Java代码:

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再试一次

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

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

我偶然发现的另一件事是绑定和侦听套接字(在 Code SOCKET 中)。此套接字侦听连接,如果工作线程需要一个新连接(在启动时或先前关闭时),则套接字 s 将下一个排队连接提供给 mConnectedSocket 以进行接收,其他连接在处理一个连接时会积压。从 Java 视图:连接了一个 Socket(设备 A)。下一个套接字(设备 B)尝试连接。-> 连接成功(如果确实发生,则在代码中正确控制)-> 随后以自然方式发送数据。(socket还在c++端的积压中)

嗯,这很难转变为我所经历的习惯。我会尽量表达我的想法。Javaside:创建 PrintWriter。输入数据并刷新。因为连接没有完全建立(C++端没有额外的connectedSocket)。冲洗不起作用。并且 onClose 套接字最终刷新其内容。

如果你这么认为,请告诉我闭嘴。我真的不知道“连接积压”在实施中的实际含义”^^

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

4

7 回答 7

2

您需要执行flush(),将数据推出。

于 2012-05-18T20:37:48.687 回答
1

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

另外(这里有线索)

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

难以置信的情况...我什至没有写设置...

WIRESHARK 会解决这个问题。

于 2012-05-24T21:34:50.767 回答
1
PrintWriter.flush();

或者使用具有自动冲洗功能的写入器。

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

于 2012-05-18T20:46:13.883 回答
0
PrintWriter pw = new PrintWriter(mSocketSend.getOutputStream(), true);
pw.println(data);
pw.flush();
于 2012-05-18T20:47:47.560 回答
0

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

可能是因为您没有打开 inputStream。试着做一个getInputStream()

否则,您是否尝试过:

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

  2. setTcpNoDelay在套接字上(虽然不应该造成几分钟的延迟!!)?

于 2012-05-18T20:49:24.977 回答
0

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

于 2012-05-19T12:10:58.340 回答
0

Actually your problem could be on the receiving end, your recv needs to be in a loop (you can google for examples of this). There is no guarantee not much each call to recv will get. If you know you are flushing the data on the Java site, that's probably your problem.

于 2012-05-18T20:55:34.063 回答