c# - 无法使用 C# TCP 服务器和 C++ TCP 客户端接收消息

标签 c# c++ sockets tcp winsock

我有一个C# TCP 服务器和一个C++ TCP 客户端(使用winsock2)。我正在尝试发送多条消息,但只收到第一条消息...

C# 服务器代码

IPAddress raw = IPAddress.Parse("127.0.0.1");
IPEndPoint ip = new IPEndPoint(raw, 7777);

Socket client = new Socket(ip.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
client.Bind(ip);
client.Listen(69);

Console.WriteLine("Waiting for connection.");
Socket conn = client.Accept();
Console.WriteLine("Got connection");

string message;
int bytesRecv;
byte[] recvBuf = new byte[100];

bytesRecv = conn.Receive(recvBuf);
Console.WriteLine("Received message, bytes: " + bytesRecv);
message = System.Text.Encoding.UTF8.GetString(recvBuf);
Console.WriteLine(message);
Array.Clear(recvBuf, 0, recvBuf.Length);

bytesRecv = conn.Receive(recvBuf);
Console.WriteLine("Received message, bytes: " + bytesRecv);
message = System.Text.Encoding.UTF8.GetString(recvBuf);
Console.WriteLine(message);
Array.Clear(recvBuf, 0, recvBuf.Length);

bytesRecv = conn.Receive(recvBuf);
Console.WriteLine("Received message, bytes: " + bytesRecv);
message = System.Text.Encoding.UTF8.GetString(recvBuf);
Console.WriteLine(message);
Array.Clear(recvBuf, 0, recvBuf.Length);

bytesRecv = conn.Receive(recvBuf);
Console.WriteLine("Received message, bytes: " + bytesRecv);
message = System.Text.Encoding.UTF8.GetString(recvBuf);
Console.WriteLine(message);
Array.Clear(recvBuf, 0, recvBuf.Length);

Console.ReadLine();

这是 C++ 代码

#pragma once

#include "pch.h"
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <iostream>
#include <string>
#include<winsock2.h>
#include <WS2tcpip.h>

#pragma (lib, "ws2_32.lib")

using namespace std;

int main()
{
        WSAData wsaData;
        SOCKADDR_IN addr;
        int result = WSAStartup(MAKEWORD(2, 2), &wsaData);
        cout << "startup gave: " << result << endl;

        SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        addr.sin_family = AF_INET;
        addr.sin_port = htons(7777);
        addr.sin_addr.s_addr = inet_addr("127.0.0.1");

        result = connect(s, (SOCKADDR*)&addr, sizeof(addr));
        cout << "Connect gave: " << result << endl;

        int count = 0;
        char sendBuf[1024] = "Hello";
        int sendResult;
        sendResult = send(s, sendBuf, sizeof(sendBuf), 0);
        sendResult = send(s, sendBuf, sizeof(sendBuf), 0);
        sendResult = send(s, sendBuf, sizeof(sendBuf), 0);
        sendResult = send(s, sendBuf, sizeof(sendBuf), 0);
}

为什么只收到第一条消息?服务器正在接收一个 recv 语句中的所有字节,因此没有理由(据我所知)这不应该工作。谢谢!

每个服务器的接收语句都会接收 100 字节(发送的全部数量)。

最佳答案

sizeof 返回对象的大小。在这种情况下,并非所有该对象都被实际使用,但 sizeof 并不关心。它始终返回对象的大小。与

char sendBuf[1024] = "Hello";
无论使用多少个字符,

sizeof(sendBuf) 始终为 1024。这意味着

send(s, sendBuf, sizeof(sendBuf), 0);

发送 "Hello\0" 以及其他 1018 个未指定的字节(由于 char sendBuf[1024] = "Hello"; 的作用,很确定这将是所有空字符) code> 已初始化,但在 sendbuf 中找不到标准引用来证明这一点。)此代码重复 4 次,总共发送 4096 个字节。我的 .Net 不稳定,但是

byte[] recvBuf = new byte[100];
conn.Receive(recvBuf);

将接收最多 100 个字节。这是 Hello 和一堆空字符。您必须阅读其中的 10.24 篇文章才能排除所有额外的空值,从而找到下一个 Hello

所以第一个

message = System.Text.Encoding.UTF8.GetString(recvBuf);

设法打印出 Hello,但接下来的三个只看到 100 个字节的空字符。

解决方案:

仅发送您需要发送的内容。

char sendBuf[1024] = "Hello";
sendResult = send(s, sendBuf, strlen(sendBuf), 0); // send all characters up to the 
                                                   // first null character

char sendBuf[] = "Hello"; // buffer will be sized to fit string(including null)
sendResult = send(s, sendBuf, sizeof(sendBuf), 0); 

警告:

TCP/IP 是一种流式传输协议(protocol)。它没有单独消息的概念,并根据需要将单独的 send 调用混合成单个数据包或多个数据包。这意味着第一次接收可能会返回所有四个 Hello

此外,接收方永远不会真正知道他们将通过给定的 TCP 套接字读取接收到什么。一条消息可能已被分割成两个数据包以最大化吞吐量,并且其中一个数据包可能已被路由很远的距离,并且在客户端读取消息时不可用。

您需要建立并使用通信协议(protocol)来区分您的消息。发送字符串时,我更喜欢在 integer of known size 中发送字符串的大小。和字节序,然后发送字符串。接收者读取字符串的长度(并确保在继续之前获得所有长度),然后读取长度字节(同样不能多也不能少)以获取字符串。

关于c# - 无法使用 C# TCP 服务器和 C++ TCP 客户端接收消息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56137425/

相关文章:

c++ - 为每个节点分配深度

c++ - 磁盘支持的 STL 容器类?

.net - 选择用于监听响应/保持套接字打开的端口?

ruby-on-rails - 从 `rails server` 开始时,Puma 未在定义的位置创建套接字

Python套接字绑定(bind)0.0.0.0,检查传入消息

c# - 从 OperationContract 方法返回图像(WCF 服务)

c# - Winform 在 Designer 中的位置

c# - ZPL II 扩展字符

c# - 找不到类型或命名空间名称 'ObservableCollection'

c++ - 我可以实现对作为父类参数的虚函数的覆盖吗?