Java 使用线程处理套接字

Java 使用线程处理套接字,java,sockets,multithreading,Java,Sockets,Multithreading,我正在开发一个java程序,它本质上是一个聊天室。这是一个课堂作业,所以没有代码请,我只是有一些问题,确定最可行的方式来处理我需要做什么。我已经为单个客户机设置了一个服务器程序,使用线程获取数据输入流,并使用线程处理数据输出流上的发送。我现在需要做的是为每个传入请求创建一个新线程 我的想法是创建一个链表来包含客户机套接字或线程。我遇到的障碍是如何处理向所有客户发送消息的问题。如果我对每个传入消息都有一个线程,那么我如何将它发送到每个客户端套接字 我在想,如果我有一个clientsockets的l

我正在开发一个java程序,它本质上是一个聊天室。这是一个课堂作业,所以没有代码请,我只是有一些问题,确定最可行的方式来处理我需要做什么。我已经为单个客户机设置了一个服务器程序,使用线程获取数据输入流,并使用线程处理数据输出流上的发送。我现在需要做的是为每个传入请求创建一个新线程

我的想法是创建一个链表来包含客户机套接字或线程。我遇到的障碍是如何处理向所有客户发送消息的问题。如果我对每个传入消息都有一个线程,那么我如何将它发送到每个客户端套接字

我在想,如果我有一个clientsockets的linkedlist,我就可以遍历这个列表并将它发送给每个人,但是每次我都必须创建一个dataoutputstream。我可以创建dataoutputstreams的linkedlist吗?抱歉,如果这听起来像我在胡扯,但我不想只是开始编码这个,它可能会变得混乱没有一个好的计划。谢谢

编辑 我决定发布到目前为止的代码。我还没有机会测试它,所以任何评论都很好。谢谢

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.ServerSocket;
import java.util.LinkedList;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class prog4_server {

    // A Queue of Strings used to hold out bound Messages
    // It blocks till on is available
    static BlockingQueue<String> outboundMessages = new LinkedBlockingQueue<String>();

    // A linked list of data output streams
    // to all the clients
    static LinkedList<DataOutputStream> outputstreams;

    // public variables to track the number of clients
    // and the state of the server
    static Boolean serverstate = true;
    static int clients = 0;

    public static void main(String[] args) throws IOException{

        //create a server socket and a clientSocket
        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket(6789);
        } catch (IOException e) {
            System.out.println("Could not listen on port: 6789");
            System.exit(-1);
        }// try{...}catch(IOException e){...}

        Socket clientSocket;

        // start the output thread which waits for elements
        // in the message queue
        OutputThread out = new OutputThread();
        out.start();

        while(serverstate){

            try {

                // wait and accept a new client
                // pass the socket to a new Input Thread
                clientSocket = serverSocket.accept();
                DataOutputStream ServerOut = new DataOutputStream(clientSocket.getOutputStream());
                InputThread in = new InputThread(clientSocket, clients);
                in.start();
                outputstreams.add(ServerOut);

            } catch (IOException e) {

                System.out.println("Accept failed: 6789");
                System.exit(-1);
            }// try{...}catch{..}

            // increment the number of clients and report
            clients = clients++;

            System.out.println("Client #" + clients + "Accepted");

        }//while(serverstate){...

    }//public static void main

    public static class OutputThread extends Thread {

        //OutputThread Class Constructor
        OutputThread() {
        }//OutputThread(...){...

        public void run() {

            //string variable to contain the message
            String msg = null;

            while(!this.interrupted()) {

                try {

                    msg = outboundMessages.take();

                    for(int i=0;i<outputstreams.size();i++){

                        outputstreams.get(i).writeBytes(msg + '\n');

                    }// for(...){...

                 } catch (IOException e) {

                    System.out.println(e);

                 } catch (InterruptedException e){

                     System.out.println(e);

                 }//try{...}catch{...}

            }//while(...){

        }//public void run(){...

    }// public OutputThread(){...

    public static class InputThread extends Thread {

        Boolean threadstate = true;
        BufferedReader ServerIn;
        String user;
        int threadID;
        //SocketThread Class Constructor
        InputThread(Socket clientSocket, int ID) {

            threadID = ID;

            try{
                ServerIn = new BufferedReader(
                    new InputStreamReader(clientSocket.getInputStream()));
                    user = ServerIn.readLine();
            }
            catch(IOException e){
                System.out.println(e);
            }

        }// InputThread(...){...

        public void run() {

            String msg = null;

        while (threadstate) {

                try {

                    msg = ServerIn.readLine();

                    if(msg.equals("EXITEXIT")){

                        // if the client is exiting close the thread
                        // close the output stream with the same ID
                        // and decrement the number of clients
            threadstate = false;
                        outputstreams.get(threadID).close();
                        outputstreams.remove(threadID);
                        clients = clients--;
                        if(clients == 0){
                            // if the number of clients has dropped to zero
                            // close the server
                            serverstate = false;
                            ServerIn.close();
                        }// if(clients == 0){...
                    }else{

                        // add a message to the message queue
                        outboundMessages.add(user + ": " + msg);

                    }//if..else...

                } catch (IOException e) {

                    System.out.println(e);

                }// try { ... } catch { ...}

        }// while

        }// public void run() { ...
    }

    public static class ServerThread extends Thread {

        //public variable declaration
        BufferedReader UserIn =
                new BufferedReader(new InputStreamReader(System.in));

        //OutputThread Class Constructor
        ServerThread() {

        }//OutputThread(...){...

        public void run() {

            //string variable to contain the message
            String msg = null;

            try {

                //while loop will continue until
                //exit command is received
                //then send the exit command to all clients

                msg = UserIn.readLine();

                while (!msg.equals("EXITEXIT")) {

                    System.out.println("Enter Message: ");
                    msg = UserIn.readLine();

                }//while(...){

                outboundMessages.add(msg);
                serverstate = false;
                UserIn.close();

            } catch (IOException e) {
                System.out.println(e);

            }//try{...}catch{...}


        }//public void run(){...
    }// public serverThread(){...

}// public class prog4_server
导入java.io.BufferedReader;
导入java.io.DataOutputStream;
导入java.io.IOException;
导入java.io.InputStreamReader;
导入java.net.Socket;
导入java.net.ServerSocket;
导入java.util.LinkedList;
导入java.util.concurrent.BlockingQueue;
导入java.util.concurrent.LinkedBlockingQueue;
公共类prog4_服务器{
//用于保存绑定消息的字符串队列
//它会一直阻塞到可用为止
静态BlockingQueue outboundMessages=新建LinkedBlockingQueue();
//数据输出流的链接列表
//给所有的客户
静态LinkedList输出流;
//用于跟踪客户端数量的公共变量
//以及服务器的状态
静态布尔serverstate=true;
静态int客户端=0;
公共静态void main(字符串[]args)引发IOException{
//创建服务器套接字和客户端套接字
ServerSocket ServerSocket=null;
试一试{
serverSocket=新的serverSocket(6789);
}捕获(IOE异常){
System.out.println(“无法侦听端口:6789”);
系统退出(-1);
}//尝试{…}捕获(IOE异常){…}
插座客户端插座;
//启动等待元素的输出线程
//在消息队列中
OutputThread out=新的OutputThread();
out.start();
while(服务器状态){
试一试{
//等待并接受新客户机
//将套接字传递给新的输入线程
clientSocket=serverSocket.accept();
DataOutputStream ServerOut=新的DataOutputStream(clientSocket.getOutputStream());
InputThread in=新的InputThread(clientSocket,客户端);
in.start();
添加(ServerOut);
}捕获(IOE异常){
System.out.println(“接受失败:6789”);
系统退出(-1);
}//试试{…}抓住{…}
//增加客户端和报告的数量
客户=客户++;
System.out.println(“Client#“+clients+“Accepted”);
}//而(服务器状态){。。。
}//公共静态真空总管
公共静态类OutputThread扩展线程{
//OutputThread类构造函数
OutputThread(){
}//输出线程(…){。。。
公开募捐{
//字符串变量以包含消息
字符串msg=null;
而(!this.interrupted()){
试一试{
msg=outboundMessages.take();

对于(int i=0;i我过去通过为每个客户端连接定义一个“
MessageHandler
”类来解决这个问题,该类负责入站/出站消息通信。在内部,处理程序使用一个
BlockingQueue
实现,出站消息放置在该实现上(通过内部工作线程)。I/O发送方线程不断尝试从队列中读取(如果需要,则阻塞),并将检索到的每条消息发送到客户端

下面是一些框架示例代码(未经测试):

/**
*我们的消息定义。消息能够将自身写入
*数据输出流。
*/
公共接口消息{
void writeTo(DataOutputStream daos)抛出IOException;
}
/**
*处理程序定义。处理程序包含两个线程:一个用于发送
*一个用于接收信息。它是用一个打开的插座初始化的。
*/    
公共类MessageHandler{
专用最终数据输出流daos;
专用最终数据输入流dais;
私有最终线程发送器;
专用终线程接收器;
private final BlockingQueue outboundMessages=新建LinkedBlockingQueue();
公共消息处理程序(套接字skt)引发IOException{
this.daos=新的DataOutputStream(skt.getOutputStream());
this.dais=新的DataInputStream(skt.getInputStream());
//创建负责执行I/O的发送方和接收方线程。
this.sender=新线程(new Runnable()){
公开募捐{
而(!Thread.interrupted()){
Message msg=outboundMessages.take();//将被阻止,直到消息可用为止。
试一试{
msg.writeTo(daos);
}捕获(IOEX异常){
//TODO:处理异常
}
}
}
},String.format(“SenderThread-%s”,skt.getRemoteSocketAddress());
this.receiver=新线程(new Runnable()){
公开募捐{
//TODO:读取DataInputStream并创建入站消息。
}
},String.format(“ReceiverThread-%s”,skt.getRemoteSocketAddress());
sender.start();
receiver.start();
}
/**
*向我提交一份报告
/**
 * Our Message definition.  A message is capable of writing itself to
 * a DataOutputStream.
 */
public interface Message {
  void writeTo(DataOutputStream daos) throws IOException;
}

/**
 * Handler definition.  The handler contains two threads: One for sending
 * and one for receiving messages.  It is initialised with an open socket.
 */    
public class MessageHandler {
  private final DataOutputStream daos;
  private final DataInputStream dais;
  private final Thread sender;
  private final Thread receiver;
  private final BlockingQueue<Message> outboundMessages = new LinkedBlockingQueue<Message>();

  public MessageHandler(Socket skt) throws IOException {
    this.daos = new DataOutputStream(skt.getOutputStream());
    this.dais = new DataInputStream(skt.getInputStream());

    // Create sender and receiver threads responsible for performing the I/O.
    this.sender = new Thread(new Runnable() {
      public void run() {
        while (!Thread.interrupted()) {
          Message msg = outboundMessages.take(); // Will block until a message is available.

          try {
            msg.writeTo(daos);
          } catch(IOException ex) {
            // TODO: Handle exception
          }
        }
      }
    }, String.format("SenderThread-%s", skt.getRemoteSocketAddress()));

    this.receiver = new Thread(new Runnable() {
      public void run() {
        // TODO: Read from DataInputStream and create inbound message.
      }
    }, String.format("ReceiverThread-%s", skt.getRemoteSocketAddress()));

    sender.start();
    receiver.start();
  }

  /**
   * Submits a message to the outbound queue, ready for sending.
   */
  public void sendOutboundMessage(Message msg) {
    outboundMessages.add(msg);
  }

  public void destroy() {
    // TODO: Interrupt and join with threads.  Close streams and socket.
  }
}