Java套接字(服务器)和C++套接字(客户端)之间的网络通信

3

我知道这可能是一个很普遍的问题,但我一直没有找到如何解决它的明确答案。

首先,假设我们有一个接受查询的Java服务器,例如(我只列出了相关行,并为清晰起见省略了异常处理):

    ServerSocket socket = new ServerSocket(port);
    while (true) {
        ClientWorker w;
        w = new ClientWorker(socket.accept());
        Thread t = new Thread(w);
        t.start();
    }

然后在ClientWorker中

    BufferedReader inFromClient = new BufferedReader(new InputStreamReader(client.getInputStream()));
    DataOutputStream outToClient = new DataOutputStream(client.getOutputStream());

    String query = inFromClient.readLine();
    // process query here
    String response = "testresponse";

    outToClient.writeBytes(response + "\n");

    outToClient.close();
    inFromClient.close();
    client.close();

现在我可以获取一个能够与此服务器配合工作的Java客户端:

String query = "testquery";
Socket queryProcessorSocket = new Socket(queryIp,queryPort);
DataOutputStream queryProcessorDos = new DataOutputStream(queryProcessorSocket.getOutputStream());
BufferedReader queryProcessorReader = new BufferedReader(new InputStreamReader(queryProcessorSocket.getInputStream()));
queryProcessorDos.writeBytes(query + "\n");
String response = queryProcessorReader.readLine();

但是如何让C ++客户端做到与Java客户端相同的事情呢?我尝试了很多方法,但似乎没有什么作用。最理想的情况是我不想接触Java服务器,这可行吗?如果有人能指向一个好的例子或一些示例代码,那将不胜感激。我搜索了很多网站,但都没有结果。

5个回答

6

在这里,我提供简单的代码来连接到服务器。如果您遇到此问题,这可能会对您有所帮助。

void client(const char* server_address, short server_port)
{
     int     sockfd;
     struct sockaddr_in servaddr;

     sockfd = socket(AF_INET, SOCK_STREAM, 0);

     memset(&servaddr, 0x00, sizeof(servaddr));
     servaddr.sin_family = AF_INET;
     servaddr.sin_port = htons(server_port);
     inet_pton(AF_INET, server_address, &servaddr.sin_addr);

     connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr));

     //from this point you can start write to the server and wait for its respose

     std::string buffer = "testquery";
     writen(sockfd, buffer.c_str(), buffer.length());

     char *ReadBuffer[512];
     while(1)
     {
         memset(ReadBuffer, 0x00, sizeof(ReadBuffer));
         int n = readn(sockfd, ReadBuffer, sizeof(ReadBuffer));
         if(n <= 0)
         {
             //or you dont have anything to read, or you have a problem
             break;
         }
         //this function does the hard job of knowing what to do with all these data
         processBuffer(ReadBuffer, n);
     }

 close(sockfd);

 }

我使用Posix标准,代码非常简化,但我认为这是一个起点。
问候。

不错的例子,尽管你应该真正记住检查返回代码,特别是检查错误代码。如果发生错误并且您没有检查连接是否成功,您的循环将结束。在网络编程中,绝对必要始终知道实际上有多少数据在您的缓冲区中,也不要假设事情是以空字符结尾的。此外,在一侧进行多次发送调用可能会导致这些缓冲区被连接起来,以便您可以在另一侧的一个读取中获取所有数据。 - Jeff Tucker
有一些小问题:你总是写512而不是sizeof(ReadBuffer),这有点奇怪。另外,如果read()遇到EINTR会怎么样? - asveikau
@Jeff:实际上,从阅读代码示例中我假定processBuffer()会处理错误,并可能将任何部分完成的请求拆分到多个读取的独立堆缓冲区中,在下一次读取时进行处理。至少,我会这样做。 - asveikau
是的,正如我所说,这段代码非常简化。当然,它应该得到很大的改进。我认为它只是一个起点的例子,而不是最终解决方案。 - Andres
你可能想要包含writen()readn()的代码,或者提到它们来自哪里(UNIX网络编程,如果我没记错的话)。 - D.Shawley

2
你说的“它不工作”是什么意思?
没有仔细研究代码,我首先关注的是你将字符串(以字符或字节对形式)转换为字节,然后将其发送到套接字。在 C++ 端是否以相同方式检索这些内容?即使用相同的字符编码?

我将补充这个答案,说Java使用Unicode(UTF-16)来存储字符。因此,在发送之前,您可以将Java字符串转换为ANSI,或者在C++客户端端使用std::wstring。 - Adrien Plisson

1
只要你不使用特定于语言的协议(例如Java RMI),而是使用直接的套接字(或类似Web服务的其他语言中立协议),那么它就可以工作。您只需要确保客户端和服务器正在使用相同的协议(例如TCP/IP +您的自定义协议)。如果使用直接的套接字,则基本上是通过电线发送二进制数据-因此,您需要确保在两侧对数据进行编码/解码相同。通常情况下,如果要自行编写,可以使用某种字节级协议来完成此操作。例如 Project Dark Star是使用Java编写的游戏服务器,但其客户端可以使用Java、C/C++、Flash等语言。它使用用户定义的二进制协议进行跨语言通信。

0

是的,您可以让C++客户端(或C客户端、COBOL客户端、Perl客户端、Ruby客户端或其他客户端)与Java服务器通信。您所要做的就是将Java代码移植到相应的C++代码(或C代码、COBOL代码、Perl代码、Ruby代码或其他代码)。服务器不知道也不关心客户端使用的编程语言。

我建议您先参考Internet Sockets,然后再使用POSIX API文档。


0

我之前也遇到过同样的问题。客户端是基于C++的,必须连接到我的基于Java的服务器,两者都在Windows上运行。我曾经为Java服务器在客户端连接时为什么会断开连接而感到困惑了很长时间。

后来我意识到这是由于大小端问题引起的。Java虚拟机=大端,C++(在我的硬件上)是小端。虽然是个小问题,但对于我这个业余爱好者来说,花了一段时间才弄清楚。


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