c# - 从 C++ 向 C# 发送消息

标签 c# c++ sockets networking

我有一个 C++ 客户端程序(用 VS2005 编写),我想向 C# 服务器程序(用 VS2017 编写)发送消息。虽然建立了连接,但消息似乎没有传到服务器,我正在努力找出原因。谁能帮我找出哪里出了问题?

测试服务器.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);
        }
    }
}

测试客户端.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
    }
}

最佳答案

在客户端,您没有检查 send() 的返回值来确保所有 256 个字节都已实际发送。它可能会返回更少的字节。在这种情况下,您必须在循环中调用 send(),直到发送完所有字节。

在服务器端,它正在尝试执行 8192 字节的初始读取(ReceiveBufferSize 的默认值),而不是 256 字节。而且,它期望客户端发送多个字符串,但客户端只发送 1 个字符串。

尝试更像这样的东西:

测试服务器.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);
        }
    }
}

测试客户端.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;
}

关于c# - 从 C++ 向 C# 发送消息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43789410/

相关文章:

c# - 全局 asax 文件

c++ - 如何将 std::valarray<double> 与 gsl 集成?

C++ 函数检查 char 是否为大写字母并计算给定字符串中大写字母的数量

sockets - ZeroMQ:如何将消息发送到特定的订户

java - Java Sockets 默认实现什么 ARQ 协议(protocol)?

c# - 在 Web API 操作中返回时,某些属性不会被序列化

c# - 当 Web 服务返回结果时,您如何检测连接何时中断?

c# - 计算通用列表中存在的字典中值的总和

c++ - 如何找到 vector 的统计信息?最大值/最小值、众数、中值、平均值

sockets - 发送数据后,JMeter TCP Sampler 不会关闭套接字