Reputation: 3
I have a C++ client program (written in VS2005), which I want to send a message to a C# server program (written in VS2017). Although a connection is established, the message does not seem to be coming through to the server, and I am struggling to figure out why. Can anyone please help me identify where it is going wrong?
TestServer.CS
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Threading;
using System.IO;
using System.Collections;
using System.Net;
class TcpServer
{
private TcpListener _server;
private Boolean _isRunning;
public TcpServer(int port)
{
_server = new TcpListener(IPAddress.Any, port);
_server.Start();
_isRunning = true;
LoopClients();
}
public void LoopClients()
{
while (_isRunning)
{
// wait for client connection
TcpClient newClient = _server.AcceptTcpClient();
// client found.
// create a thread to handle communication
Thread t = new Thread(new ParameterizedThreadStart(HandleClient));
t.Start(newClient);
}
}
public void HandleClient(object obj)
{
// retrieve client from parameter passed to thread
TcpClient client = (TcpClient)obj;
//
int i = 0;
string data = null;
Byte[] bytes = new Byte[256];
Stream s = client.GetStream();
StreamReader Reader = new StreamReader(s);
StreamWriter Writer = new StreamWriter(s);
Writer.NewLine = "\r\n";
Writer.AutoFlush = true;
byte[] serverData = new byte[client.ReceiveBufferSize];
int length = s.Read(serverData, 0, serverData.Length);
string received = Encoding.ASCII.GetString(serverData, 0, length);
while ((i = s.Read(bytes, 0, bytes.Length)) != 0)
{
// Translate data bytes to a ASCII string.
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
Console.WriteLine("Received: {0}", data);
// Process the data sent by the client.
data = data.ToUpper();
byte[] msg = System.Text.Encoding.ASCII.GetBytes(data);
// Send back a response.
s.Write(msg, 0, msg.Length);
Console.WriteLine("Sent: {0}", data);
}
}
}
namespace Multi_Threaded_TCP
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Multi-Threaded TCP Server Demo");
TcpServer server = new TcpServer(1111);
}
}
}
TestClient.cpp
#pragma comment(lib,"ws2_32.lib")
#include <WinSock2.h>
#include <iostream>
int main()
{
//Winsock Startup
WSAData wsaData;
WORD DllVersion = MAKEWORD(2, 1);
if (WSAStartup(DllVersion, &wsaData) != 0) //If WSAStartup returns anything other than 0, then that means an error has occured in the WinSock Startup.
{
MessageBoxA(NULL, "Winsock startup failed", "Error", MB_OK | MB_ICONERROR);
exit(1);
}
SOCKADDR_IN addr; //Address to be binded to our Connection socket
int sizeofaddr = sizeof(addr); //Need sizeofaddr for the connect function
addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //Address = localhost (this pc)
addr.sin_port = htons(1111); //Port = 1111
addr.sin_family = AF_INET; //IPv4 Socket
SOCKET Connection = socket(AF_INET, SOCK_STREAM, NULL); //Set Connection socket
if (connect(Connection, (SOCKADDR*)&addr, sizeofaddr) != 0) //If we are unable to connect...
{
MessageBoxA(NULL, "Failed to Connect", "Error", MB_OK | MB_ICONERROR);
return 0; //Failed to Connect
}
else
{
std::cout << "Connected!" << std::endl;
}
char MOTD[256] = "Hello there Server, Please run task a & b":) //Create buffer with message
send(Connection, MOTD, sizeof(MOTD), NULL);
while (true)
{
Sleep(10); // keep program running
}
}
Upvotes: 0
Views: 1939
Reputation: 595402
On the client side, you are not checking the return value of send()
to make sure all 256 bytes were actually sent. It may return fewer bytes instead. In which case, you have to call send()
in a loop until all bytes have been sent.
On the server side, it is trying to perform an initial read of 8192 bytes (the default value of ReceiveBufferSize
), not 256 bytes. But also, it is expecting the client to send multiple strings, but the client is only sending 1 string.
Try something more like this instead:
TestServer.CS
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Threading;
using System.IO;
using System.Collections;
using System.Net;
class TcpServer
{
private TcpListener _server;
private Boolean _isRunning;
public TcpServer(int port)
{
_server = new TcpListener(IPAddress.Any, port);
_server.Start();
_isRunning = true;
LoopClients();
}
public void LoopClients()
{
while (_isRunning)
{
// wait for client connection
TcpClient newClient = _server.AcceptTcpClient();
// client found.
// create a thread to handle communication
Thread t = new Thread(new ParameterizedThreadStart(HandleClient));
t.Start(newClient);
}
}
private byte[] ReadBytes(Stream s, int length)
{
byte[] bytes = new byte[length];
int read, total = 0;
while (total < length)
{
read = s.Read(bytes, total, length - total);
if (read == 0)
return null;
total += read;
}
return bytes;
}
private void SendBytes(Stream s, byte[] bytes)
{
int total = 0;
while (total < bytes.length)
{
total += s.Write(bytes, total, bytes.length - total);
}
}
private bool ReadUInt32(Stream s, out uint value)
{
byte[] bytes = ReadBytes(s, 4);
if (bytes == null)
return false;
if (BitConverter.IsLittleEndian)
Array.Reverse(bytes);
value = BitConverter.ToUInt32(bytes, 0);
return true;
}
private void SendUInt32(Stream s, uint value)
{
byte[] bytes = BitConverter.GetBytes(value);
if (BitConverter.IsLittleEndian)
Array.Reverse(bytes);
SendBytes(s, bytes);
}
private bool ReadString(Stream s, out string value)
{
value = "";
uint length;
if (!ReadUInt32(s, length))
return false;
if (length > 0)
{
byte[] bytes = ReadBytes(s, length);
if (bytes == null)
return false;
value = System.Text.Encoding.UTF8.GetString(bytes);
}
return true;
}
private void SendString(Stream s, string value)
{
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(value);
SendUInt32(s, bytes.length);
SendBytes(s, bytes);
}
public void HandleClient(object obj)
{
// retrieve client from parameter passed to thread
TcpClient client = (TcpClient)obj;
Stream s = client.GetStream();
string data;
while (ReadString(s, data))
{
Console.WriteLine("Received: {0}", data);
// Process the data sent by the client.
data = data.ToUpper();
// Send back a response.
SendString(s, data);
Console.WriteLine("Sent: {0}", data);
}
}
}
namespace Multi_Threaded_TCP
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Multi-Threaded TCP Server Demo");
TcpServer server = new TcpServer(1111);
}
}
}
TestClient.cpp
#include <windows.h>
#include <winsock2.h>
#include <iostream>
#include <string>
#pragma comment(lib,"ws2_32.lib")
bool readRaw(SOCKET s, void *data, int len)
{
char *ptr = (char*) data;
while (len > 0)
{
int read = recv(s, ptr, len, 0);
if (read <= 0)
return false;
ptr += read;
len -= read;
}
return true;
}
bool sendRaw(SOCKET s, const void *data, int len)
{
const char *ptr = (const char*) data;
while (len > 0)
{
int sent = send(s, ptr, len, 0);
if (sent < 0)
return false;
ptr += sent;
len -= sent;
}
return true;
}
bool readUInt32(SOCKET s, ulong &value)
{
if (!readRaw(s, &value, sizeof(value)))
return false;
value = ntohl(value);
return true;
}
bool sendUInt32(SOCKET s, ulong value)
{
value = htonl(value);
return sendRaw(s, &value, sizeof(value));
}
bool readString(SOCKET s, std::wstring &str)
{
str.clear();
ulong utf8len;
if (!readUInt32(s, utf8len))
return false;
if (utf8len > 0)
{
std::string utf8;
utf8.resize(utf8len);
if (!readRaw(s, &utf8[0], utf8len))
return false;
int len = MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), utf8.length(), NULL, 0);
if (len > 0)
{
str.resize(len);
MultiBytetoWideChar(CP_UTF8, 0, utf8.c_str(), utf8.length(), &str[0], len);
}
}
return true;
}
bool sendString(SOCKET s, const std::wstring &str)
{
std::string utf8;
int len = WideCharToMultiByte(CP_UTF8, 0, str.c_str(), str.length(), NULL, 0, NULL, NULL);
if (len > 0)
{
utf8.resize(len);
WideCharToMultiByte(CP_UTF8, 0, str.c_str(), str.length(), &utf8[0], len, NULL, NULL);
}
if (!sendUInt32(s, utf8.length()))
return false;
return sendRaw(s, utf8.c_str(), utf8.length());
}
int main()
{
//Winsock Startup
WSAData wsaData;
if (WSAStartup(MAKEWORD(2, 1), &wsaData) != 0) //If WSAStartup returns anything other than 0, then that means an error has occured in the WinSock Startup.
{
MessageBoxA(NULL, "Winsock startup failed", "Error", MB_OK | MB_ICONERROR);
return 1;
}
SOCKET Connection = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //Set Connection socket
if (Connection == INVALID_SOCKET)
{
WSACleanup();
MessageBoxA(NULL, "Winsock socket failed", "Error", MB_OK | MB_ICONERROR);
return 1;
}
SOCKADDR_IN addr; //Address to be binded to our Connection socket
addr.sin_family = AF_INET; //IPv4 Socket
addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //Address = localhost (this pc)
addr.sin_port = htons(1111); //Port = 1111
if (connect(Connection, (SOCKADDR*)&addr, sizeof(addr)) != 0) //If we are unable to connect...
{
MessageBoxA(NULL, "Failed to Connect", "Error", MB_OK | MB_ICONERROR);
}
else
{
std::cout << "Connected!" << std::endl;
do
{
std::cout << "Enter a string to send:" << std::endl;
std::wstring msg;
if (!std::getline(std::wcin, msg))
break;
if (!sendString(Connection, msg))
{
MessageBoxA(NULL, "Failed to Send", "Error", MB_OK | MB_ICONERROR);
break;
}
if (!readString(Connection, msg))
{
MessageBoxA(NULL, "Failed to Read", "Error", MB_OK | MB_ICONERROR);
break;
}
std::wcout << "Received:" << std::endl << msg << std::endl;
}
while (true);
}
closesocket(Connection);
WSACleanup();
return 0;
}
Upvotes: 1