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

时间:2019-05-14 19:33:52

标签: 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字节(已发送的全部数据)。

1 个答案:

答案 0 :(得分:2)

sizeof返回对象的大小。在这种情况下,并非实际上所有对象都在使用,但是sizeof不在乎。它总是返回对象的大小。使用

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

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

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

发送"Hello\0"以及其他1018个未指定的字节(由于char sendBuf[1024] = "Hello";的初始化方式,所以肯定会全部为空字符),但是找不到。 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是流协议。它没有单个消息的概念,并且可以根据需要将对send的单个调用愉快地合并到一个或多个数据包中。这意味着第一次接收可能会返回所有四个 Hello

此外,在给定的TCP套接字读取的情况下,接收方永远不会真正知道要接收的内容。一条消息可能已被拆分为两个数据包以最大化吞吐量,并且其中一个数据包可能已路由很长的距离,并且在客户端读取该消息时不可用。

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