Java和C++之间的Socket通信

4

我希望将Java服务器和C++客户端建立连接。但是当我在客户端读取数据时,总是出现相同的奇怪字符(¬í)。我尝试在两端更改编码,但都没有起作用。

这是我的Java代码:

public class Serveur
{
    public static void main(String[] args) throws Exception
    {
        final int PORT = 13370;
        try
        {
            ServerSocket service= new ServerSocket(PORT);
            Socket connection = service.accept();
            PrintWriter pw = new PrintWriter(connection.getOutputStream());
            String s = Integer.toString(5);
            while(true)
            {
                pw.print(s.getBytes("UTF-8"));
                pw.flush();
                pw.close();
            }
            connection.close();
        }
}

我尝试使用OutputStream、DataOutputStream和BufferedOutputStream。以下是C++代码:
int main(int argc, char* argv[])
{
    WSADATA WSAData;
    WSAStartup(MAKEWORD(2,0), &WSAData);
    SOCKET sock;
    SOCKADDR_IN sin;
    char buffer[512];
    sin.sin_addr.s_addr = inet_addr("127.0.0.1");
    sin.sin_family      = AF_INET;
    sin.sin_port        = htons(13370);
    sock = socket(AF_INET,SOCK_STREAM,0);
    if(connect(sock, (SOCKADDR*)&sin, sizeof(sin)) != SOCKET_ERROR)
{
    cout<<"connection"<<endl;
    if(recv(sock, buffer, sizeof(buffer), 0) != SOCKET_ERROR)
    {
        string s = buffer;
        wchar_t *pwchello = L"Hi";
        wchar_t *pwc      = (wchar_t *)malloc( sizeof( wchar_t ));
        char    *pmbhello = buffer;
        int i = mbstowcs(pwc,pmbhello, MB_CUR_MAX);
        cout << i << endl;
        cout<<"cout : "<<pwc<<endl;
        cout <<buffer<<endl;
        printf("printf : %s\n", buffer);

        cout << "wsagetlasterror() : "<<WSAGetLastError();
        closesocket(sock);
        WSACleanup();
        free(m_pBuffer);
    }
    return 0;
}

正如您所看到的,我尝试了不同的解决方案,但都没有成功。

提前感谢您,对于我的英语可能不是很好,我很抱歉。


这是C还是C++?看起来像是C,因为你在使用malloc - netcoder
这是WinAPI吗?也许你想将其标记为这样的?无论如何,对于这样的事情,了解如何使用诸如Wireshark之类的工具非常有用,以便您可以查看实际上在传输中的内容,以确定首先查看哪个程序。 - PlasmaHH
可能是因为UTF-8编码,我会尝试使用ASCII编码。 - user591593
@netcoder 除非这是C语言,否则它将无法编译通过。承认吧,你所嘲笑的那些“丑陋”的东西都是你选择的编程语言的一部分。 :-) 现在,“惯用语”或具有适当的C++风格是另一个问题... - asveikau
实际上,在C++中也不能编译。 缺少一个 } - netcoder
在Java端,您正在打印一个byte[];这可能不是您想要的。只需打印数字即可。 - kdgregory
4个回答

2

recv函数不会将目标缓冲区转换为以null结尾的字符串。它会在缓冲区中填充一定数量的字节,但不会追加0。

你需要这样做(当然要进行错误检查):

ssize_t bytesRead = recv(buffer, ...);
string str(buffer, bytesRead);

此外,请注意,recv不能保证一次发送的内容只接收一次(除非您正在使用UDP)。

如果我总是发送一个简单的整数或字符串,它是否可以在一次调用中接收到? 我如何选择UDP和TCP之间的区别? - pikmin
TCP传递一系列字节,而UDP传递一系列数据包(字节数组)。UDP提供内置的消息“边界”(一个数据包是一个消息,最多64K字节作为一个单元传递),而使用TCP需要在应用程序级别上将流分割成消息(例如通过将每4个字节视为单个消息或在消息之间插入0)。 TCP保证传递:您可以获得正确顺序的每个字节,否则您将失去连接。 UDP允许丢弃数据包。 - user3458
关于发送“简单整数或字符串”,实际上没有任何保证。你传递给send()的数据越小,它被一次recv()接收的可能性就越大。然而,这完全取决于时间和数据包边界。你传递给send()的数据将被分成数据包通过IP进行传输,而recv()将返回到目前为止已经到达的所有数据包中的数据。 - user3458

2

您可能混淆了很多不同的编码转换和I/O策略。您可以尝试以下简化版本:

if(connect(sock, (SOCKADDR*)&sin, sizeof(sin)) != SOCKET_ERROR)
{
    cout << "connection" << endl;

    // the result of 'recv()' is either SOCKET_ERROR or
    // the number of bytes received.  don't though away
    // the return value.
    const int result = recv(sock, buffer, sizeof(buffer), 0);
    if(result != SOCKET_ERROR)
    {
        // use length (in bytes) returned by 'recv()'
        // since buffer is not null terminated.
        string s(buffer,result);

        // 's' is in UTF-8 no converstion to wide strings
        // should be necessary.
        cout << "message: '" << s << "'." << endl;
    }

    closesocket(sock);
}
WSACleanup();

请注意,标准输出是在当前代码页中进行的,通常情况下UTF-8不是默认的代码页。在Windows控制台中输出Unicode数据需要使用其他几个库函数进行配置。


0

这里你只为一个wchar_t分配了空间:

wchar_t *pwc = (wchar_t *)malloc( sizeof( wchar_t ));

你还将缓冲区分配给字符串s,但似乎从未使用过s。


0

我从昨晚开始一直遇到同样的问题。最终发现我的服务器(用C语言编写)无法识别编码。因此,我在客户端进行了更改。

someOutputStream.writeUTF(someSillyString);

someOutputStream.write(someSillyString.getBytes());

这样,我甚至不需要在服务器端进行类型转换。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接