I have a C# TCP server and a C++ TCP client (using winsock2). I'm trying to send multiple messages but only the first one is being received...
C# server code
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();
And here's the C++ code
#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);
}
Why is only the first message received? The sever is receiving all of the bytes in one recv statement so there is no reason (that I know of) that this shouldn't work. Thanks!
100 Bytes (full amount sent) are received on each of the server's receive statements.
sizeof
returns the size of an object. In this case not all of that object is actually being used, but sizeof
does not care. It always returns the size of the object. With
char sendBuf[1024] = "Hello";
sizeof(sendBuf)
is always 1024 no matter how many characters are being used. This means
send(s, sendBuf, sizeof(sendBuf), 0);
sends "Hello\0"
along with the other 1018 unspecified bytes (Pretty sure this will be all null characters thanks to how char sendBuf[1024] = "Hello";
is initialized, but can't find the Standard quote to prove it.) in sendbuf. This code is repeated 4 times for a grand total of 4096 bytes sent. My .Net is shaky, but
byte[] recvBuf = new byte[100];
conn.Receive(recvBuf);
will receive up to 100 bytes. That's Hello and a bucket load of null characters. You'll have to read 10.24 of these to get through all of the extra nulls to find the next Hello.
so the first
message = System.Text.Encoding.UTF8.GetString(recvBuf);
manages to print out Hello, but the next three see nothing but 100 bytes of null characters.
Solution:
Only send what you need to send.
char sendBuf[1024] = "Hello";
sendResult = send(s, sendBuf, strlen(sendBuf), 0); // send all characters up to the
// first null character
or
char sendBuf[] = "Hello"; // buffer will be sized to fit string(including null)
sendResult = send(s, sendBuf, sizeof(sendBuf), 0);
Caveat:
TCP/IP is a streaming protocol. It has no concept of individual messages and gleefully mashes individual calls to send
into a single packet or more packets as required. This means the first receive is likely to return all four Hellos.
In addition, the receiver never really knows what they are going to receive with a given TCP socket read. A message may have been split across two packets to maximize throughput and one of those packets may have been routed the long way around and not be available when the client reads for the message.
You will need to establish and use a communication protocol in order to differentiate your messages. When sending strings, I prefer to send the size of the string in an integer of known size and endian and then send the string. The receiver reads the length (and makes sure it got all of the length before proceeding) of the string and then reads length bytes (again no more, no less) to get the string.