在Java中设置多客户端/服务器TCP连接

时间:2013-05-13 15:41:21

标签: java multithreading sockets networking tcp

我正在尝试用Java创建一个多客户端/服务器应用程序。我遇到了一些问题,因为我的线索似乎纠缠在一起......这就是我想要做的事情。

  1. 我有一个Server类,它使用这段代码接受客户端:

    而(真){             套接字socket = serverSocket.accept(); }

  2. 我的服务器应该记住连接的客户端,因此我使用该套接字创建一个名为ClientThread的新线程,并将该线程放在服务器上的列表中

  3. 该线程侦听从客户端发送的Command对象。如果它收到命令,则需要将其发送到Server实例以进行进一步处理(不在该ClientThread上创建新的Server实例)。我试图通过在创建时将Server-instance添加到此Thread来实现此目的。 (这是正确的方法吗?)

  4. 我的服务器也应该能够随时将对象发送回客户端(1个或更多)。我正在尝试使用保存在ClientThread中的socket.getOutputStream()

  5. 我应该如何组织我的线程,以便每个客户端始终监听从服务器接受对象,以及他们可以随时将对象发送到服务器。

    我知道这不是一个特定的问题,但是如果你知道一些可能对这个用例有用的信息或教程,我真的很感激。

    顺便说一句:我知道如何创建套接字和发送(可序列化)对象等等。我只是坚持如何组织一切

2 个答案:

答案 0 :(得分:1)

您似乎纠结了线程和对象。我会

a)确保你没有在任何地方扩展Thread或调用你的对象XxxxThread。使用ExecutorService来管理线程是一个好主意。

b)有一个简单的模型用于响应客户端命令,例如:每个客户端线程读取一个任务,然后执行任务。

c)为每个连接都有一个包装器,例如使用sendMessage方法。

答案 1 :(得分:1)

既然您已经了解了套接字和线程,我就向您发送了伪代码的想法(案例需要特定部分代码才能告诉我)

你没有提到的一件事是如何通过其IP或任何其他方法(如ID)跟踪客户端?任何给定的设备都可以使用不同的客户端ID打开多个连接吗?或者你只能接受每个设备一个连接?在任何情况下,如果客户已经在列表中,您需要做什么?你会把创建的线程传递给新套接字吗?你会破坏那个线程并创建一个新线程吗?或者你可能会忽略这个新请求?

这是我的想法(取自工作申请):

服务器准备服务器套接字并等待接受状态。

一旦客户端连接,服务器启动一个线程来参加客户端传递它刚刚使用accept命令创建的套接字。当访问客户端的线程启动时,它从客户端收到的第一条消息应该是一个密码o特殊签名,让客户端进入(这是可选的)。

服务器代码:

Prepares the server socket which listen in a well known port
Clear client list;

While (!Terminated)
{
      // if you want to impose a limit for connections, check it here:
      if (Is the list of connected client full?)
      {
           Sleep(reasonable time in seconds or miliseconds);
           continue;
       }
       ClientSocket = ServerSocket.Accept();
       if the client's IP is already in the list
       {
           depends on what you want to do.
       }
       else
       {
            Add client's IP to the list
            Start (create) new client Tread(ClientSocket);
       }
}
// when server finish
If (client list is not empty?)
{
   Kill all threads
   or
   Wait until all threads are done
   or
   Wait an amount of time and then kill those remaining.
}

线程客户端代码:

// This is optional, just to make sure a valid client is connected
Read packet from ClientSocket
if (!Is_the_passport_packet)
{
   close socket;
   return;
}

// if passport is not required, start here
Try
{
   While (!Terminated)
   {
      if (read packet from client);
      {
         switch (packet.Command)
         {
 // In your question you said you want the Server thread to process the request
 // I guess you have your requirements to do so,
 // anyway, you must use a mutex o some other synchronization method.
             case TASK_1:
                [sync] process TASK_1(packet, ClientSocket);
                break;
             case TASK_2:
                [sync] process TASK_2(packet, ClientSocket);
                break;
             etc ….

             case WORK_DONE:
                Close Socket;
                return;

             default:
                Log(received an unknown command: packet.command);
                break;

         }
      }
      else if (Client has quit (closed/broken socket))
      {
         // as you may know, a socket is consider shutdown when you received a 0 length data
         // and a broken connection when received -1 in either case all you have to do is
         Close Socket;
         return;
      }
  }
}
catch (Exception e)
{
    Log(received an exception: e.message);
}
finally
{
   Remove this client from the client's list
}