网络通信TCP [代码设计]

时间:2012-02-27 10:48:19

标签: java networking tcp udp

过去几天我一直在使用TCP / IP通信搞乱了很多(使用Java和C#)。我理解它是如何工作的并且能够使用它。我的问题更多的是一个代码设计问题,它是如何做到最好和最简单的方式来进行真正的沟通。

例如,我建立了自己的多用户聊天服务器。我希望我的通信能够决定使用Auth请求或新聊天消息来获取当前用户列表等等。

我自己实现了一些方法,但我对此并不十分满意,因为我认为这是一种更标准和美观的方式。

我的第一个想法是带有分隔符的分隔符的字符串,这是我在Java中实现我的通信的示例:

//The Object-types im Using
clientSocket = new Socket(host, port_number);
_toServer = new PrintStream(clientSocket.getOutputStream());
_fromServer = new DataInputStream(clientSocket.getInputStream());

//Example Commands my Client sends to the server

_toServer.println("STATUS|"); //Gets the Status if server is online or closed (closed can occur when server runs but chat is disabled)
_toServer.println("AUTH|user|pw"); //Sends an auth Request to Server with username and Password
_toServer.println("MESSAGE|Hello World|ALL"); //Sends hello World in the Normal Chat to all Users
_toServer.println("MESSAGE|Hello World|PRIVATE|foo"); //Sends hello World only to the user "foo"
_toServer.println("USERS|GET"); //Request a list of all Connected Users


//Example In the Recieved Message Method where all The Server Messages Get Analyzed
serverMessage = _fromServer.readLine(); //Reads the Server Messages

String action = serverMessage.split("|")[0];

if (action.equals("USERS")) { //Example "USERS|2|foo;bar"
    String users[] = serverMessage.split("|")[2].split(";");
}
if (action.equals("MESSAGE")) { //Example "MESSAGE|Hello World|PRIVATE|foo"
    if(serverMessage.split("|")[2].equals("ALL") {
        //Code and else for private....
    }
}
if (serverMessage.equals("STATUS|ONLINE")) {
    // Code
    // I leave out //Code and } for the next If statements
}
if (serverMessage.equals("STATUS|OFFLINE")) {
if (serverMessage.equals("AUTH|ACCEPTED")) {
if (serverMessage.equals("AUTH|REJECT")) {

这是通常完成的方式吗? Ad You See我需要发送与代码相对应的状态代码和对象。我想过用字节写数据并实现“每个对象的解码器”,例如:

int action = _fromServer.readInt();     

//opcodes is just an Enum Holding the corresponding int

switch(action) {
  case(opcodes.MESSAGE):
    break;
  case(opcodes.AUTH):
    break;         
 }

请注意,这不仅仅是针对此聊天服务器示例的一般设计问题,我认为我只是为实践实现一个基于网络的小型控制台游戏。

有没有更好的方法来执行此操作甚至是API / Framework?

提前致谢!

4 个答案:

答案 0 :(得分:2)

基本上你正在设计一个协议。有许多通信协议可以解决这个问题,我想到的主要问题是IRC。我相信你可以在网上搜索有关如何实施协议的提示。

至于为控制台游戏扩展这样的东西,我将首先实现IRC,并使用它来学习如何编写真正的通信协议。完成后,您可以在它上面构建,将自己的命令添加到框架中。

答案 1 :(得分:2)

如果您正在设计用于语言间通信的协议,我建议不要使用格式化字符串作为通信手段而是使用状态字节。如果您考虑TCP / IP本身的设计,您会发现,消息由固定格式的头和可变的有效载荷组成。这样你总是知道,(例如)消息的第三个字节包含消息类型,第五个字节表示错误,依此类推。这使处理更容易。

如果您已经设计了协议,则可以考虑在java端使用显式MessageObjects,在这种情况下,您将为这些对象实现具有编组和解组方法的工厂,从而将对象转换为协议中的消息。

如果你是全Java,你甚至可以省去这些努力,并在客户端和服务器上使用ObjectInputStreams和ObjectOutputStreams。如果不是,您可能需要查看Google协议缓冲区:http://code.google.com/intl/de-DE/apis/protocolbuffers/,这对于语言间通信基本相同。

答案 2 :(得分:2)

如果您的项目增长,您可能需要查看Netty - 它是处理通信代码的框架。如果您的代码很简单,那么您最好手动操作。

至于协议设计,它取决于对你最重要的东西:性能,可扩展性,人类可读性,易于调试等。这些标准可能在某种程度上相互对立,例如高性能可能意味着对二进制的偏好协议,但这些负面影响调试的简易性和有时可扩展性。不重新发明轮子通常是一个好主意。从现有协议中获得灵感。如果你选择二进制,除非你真的需要,否则不要从头开始,从Protocol Buffers开始。如果您的应用程序很简单并且不是针对非常高的性能,请使用人类可读的协议,这将使您的生活更轻松(使用stracenc等标准shell工具可以进行调试和测试。

答案 3 :(得分:1)

我认为Apache MINA会帮助你。 http://mina.apache.org/

构建Java C / S应用程序非常复杂,需要处理TCP,UDP和多线程编程; MINA可以帮助您完成这些事情。

我认为您需要的另一部分是您的私人聊天协议,但是像Jabber这样的开源IM服务怎么样? :)