• Tags ,
  •         
  • www.breakyizhan.com
  •    

    本文假设您具有java中套接字编程的基本知识以及通信中使用的客户端 - 服务器模型的基本细节。

    为什么在网络编程中使用线程?

    原因很简单,我们不希望只有一个客户端在特定时间连接到服务器,而是同时连接多个客户端。我们希望我们的架构能够同时支持多个客户端。出于这个原因,我们必须在服务器端使用线程,这样无论何时客户端请求到来,都可以分配一个单独的线程来处理每个请求。

    让我们举一个例子,假设一个日期时间服务器位于一个地方,比如说X.作为通用服务器,它不服务于任何特定的客户端,而是服务于一整套通用客户端。还假设在特定时间,两个请求到达服务器。使用我们的基本服务器 - 客户端程序,首先达到纳秒级的请求将能够连接到服务器,而其他请求将被拒绝,因为没有提供同时处理多个请求的机制。为了克服这个问题,我们在网络编程中使用线程。
    以下文章将重点介绍如何创建一个简单的日期时间服务器,以便同时处理多个客户端请求

    快速概述

    像往常一样,我们将创建两个java文件,Server.javaClient.java。服务器文件包含两个类,即Server(用于创建服务器的公共类)和ClientHandler(用于使用多线程处理任何客户端)。客户端文件只包含一个公共类Client(用于创建客户端)。下面是这三个类如何相互作用的流程图。

    在Java中使用Socket套接字编程引入多线程

    Socket套接字服务器端编程(Server.java)

    • 服务器类:服务器端涉及的步骤类似于Java中的Socket 编程一文,稍微更改一下,在获取流和端口号后创建线程对象。
      1. 建立连接:初始化服务器套接字对象,在while循环内,套接字对象不断接受传入连接。
      2. 获取Streams:输入流对象和outputstream对象是从当前请求的套接字对象中提取的。
      3. 创建处理程序对象:获取流和端口号后,将使用这些参数创建新的clientHandler对象(上述类)。
      4. 调用start()方法在这个新创建的线程对象上调用start()方法。
    • ClientHandler类:我们将为每个请求使用单独的线程,让我们了解扩展Threads的ClientHandler类的工作和实现。每次请求到来时,都会实例化该类的对象。
      1. 首先,这个类扩展了Thread,使其对象承担了Threads的所有属性。
      2. 其次,该类的构造函数接受三个参数,这些参数可以唯一地标识任何传入的请求,即Socket,要读取的DataInputStream和要写入的DataOutputStream。每当我们收到客户端的任何请求时,服务器都会提取其端口号,DataInputStream对象和DataOutputStream对象,并创建该类的新线程对象并对其调用start()方法
        注意:每个请求将始终具有套接字,输入流和输出流的三元组。这可确保此类的每个对象都写入一个特定的流而不是多个流。
      3. 在此类的run()方法内,它执行三个操作:请求用户指定是否需要时间或日期,从输入流对象读取答案,并相应地在输出流对象上写入输出。
    // Java implementation of  Server side
    // It contains two classes : Server and ClientHandler
    // Save file as Server.java
     
    import java.io.*;
    import java.text.*;
    import java.util.*;
    import java.net.*;
     
    // Server class
    public class Server 
    {
        public static void main(String[] args) throws IOException 
        {
            // server is listening on port 5056
            ServerSocket ss = new ServerSocket(5056);
             
            // running infinite loop for getting
            // client request
            while (true) 
            {
                Socket s = null;
                 
                try
                {
                    // socket object to receive incoming client requests
                    s = ss.accept();
                     
                    System.out.println("A new client is connected : " + s);
                     
                    // obtaining input and out streams
                    DataInputStream dis = new DataInputStream(s.getInputStream());
                    DataOutputStream dos = new DataOutputStream(s.getOutputStream());
                     
                    System.out.println("Assigning new thread for this client");
     
                    // create a new thread object
                    Thread t = new ClientHandler(s, dis, dos);
     
                    // Invoking the start() method
                    t.start();
                     
                }
                catch (Exception e){
                    s.close();
                    e.printStackTrace();
                }
            }
        }
    }
     
    // ClientHandler class
    class ClientHandler extends Thread 
    {
        DateFormat fordate = new SimpleDateFormat("yyyy/MM/dd");
        DateFormat fortime = new SimpleDateFormat("hh:mm:ss");
        final DataInputStream dis;
        final DataOutputStream dos;
        final Socket s;
         
     
        // Constructor
        public ClientHandler(Socket s, DataInputStream dis, DataOutputStream dos) 
        {
            this.s = s;
            this.dis = dis;
            this.dos = dos;
        }
     
        @Override
        public void run() 
        {
            String received;
            String toreturn;
            while (true) 
            {
                try {
     
                    // Ask user what he wants
                    dos.writeUTF("What do you want?[Date | Time]..\n"+
                                "Type Exit to terminate connection.");
                     
                    // receive the answer from client
                    received = dis.readUTF();
                     
                    if(received.equals("Exit"))
                    { 
                        System.out.println("Client " + this.s + " sends exit..."); 
                        System.out.println("Closing this connection.");
                        this.s.close();
                        System.out.println("Connection closed");
                        break;
                    }
                     
                    // creating Date object
                    Date date = new Date();
                     
                    // write on output stream based on the
                    // answer from the client
                    switch (received) {
                     
                        case "Date" :
                            toreturn = fordate.format(date);
                            dos.writeUTF(toreturn);
                            break;
                             
                        case "Time" :
                            toreturn = fortime.format(date);
                            dos.writeUTF(toreturn);
                            break;
                             
                        default:
                            dos.writeUTF("Invalid input");
                            break;
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
             
            try
            {
                // closing resources
                this.dis.close();
                this.dos.close();
                 
            }catch(IOException e){
                e.printStackTrace();
            }
        }
    }
    

    输出

    A new client is connected : Socket[addr=/127.0.0.1,port=60536,localport=5056]
    Assigning new thread for this client
    Client Socket[addr=/127.0.0.1,port=60536,localport=5056] sends exit...
    Closing this connection.
    Connection closed

    Socket套接字客户端编程(Client.java)

    客户端编程与一般套接字编程程序类似,具有以下步骤 -

    1. 建立Socket套接字连接
    2. 通讯
    // Java implementation for a client
    // Save file as Client.java
     
    import java.io.*;
    import java.net.*;
    import java.util.Scanner;
     
    // Client class
    public class Client 
    {
        public static void main(String[] args) throws IOException 
        {
            try
            {
                Scanner scn = new Scanner(System.in);
                 
                // getting localhost ip
                InetAddress ip = InetAddress.getByName("localhost");
         
                // establish the connection with server port 5056
                Socket s = new Socket(ip, 5056);
         
                // obtaining input and out streams
                DataInputStream dis = new DataInputStream(s.getInputStream());
                DataOutputStream dos = new DataOutputStream(s.getOutputStream());
         
                // the following loop performs the exchange of
                // information between client and client handler
                while (true) 
                {
                    System.out.println(dis.readUTF());
                    String tosend = scn.nextLine();
                    dos.writeUTF(tosend);
                     
                    // If client sends exit,close this connection 
                    // and then break from the while loop
                    if(tosend.equals("Exit"))
                    {
                        System.out.println("Closing this connection : " + s); 
                        s.close();
                        System.out.println("Connection closed");
                        break;
                    }
                     
                    // printing date or time as requested by client
                    String received = dis.readUTF();
                    System.out.println(received);
                }
                 
                // closing resources
                scn.close();
                dis.close();
                dos.close();
            }catch(Exception e){
                e.printStackTrace();
            }
        }
    }
    

    输出:

    What do you want?[Date | Time]..
    Type Exit to terminate connection.
    Date
    2017/06/16
    What do you want?[Date | Time]..
    Type Exit to terminate connection.
    Time
    05:35:28
    What do you want?[Date | Time]..
    Type Exit to terminate connection.
    Geeks
    Invalid input
    What do you want?[Date | Time]..
    Type Exit to terminate connection.
    Exit
    Closing this connection : Socket[addr=localhost/127.0.0.1,port=5056,localport=60536]
    Connection closed

    这些程序如何协同工作?

    1. 当客户端(例如client1发送连接到服务器的请求)时,服务器会分配一个新线程来处理此请求。新分配的线程被授予对与客户端通信的流的访问权。
    2. 在分配新线程之后,服务器通过其while循环再次进入接受状态。
    3. 当第一个请求仍在进行时,第二个请求到来时,服务器接受此请求并再次分配一个新线程进行处理。这样,即使某些请求正在进行中,也可以处理多个请求。

    如何在您的系统上测试上述程序?

    将两个程序保存在同一个包中或任何地方。然后首先运行Server.java,然后运行Client.java。您可以将客户端程序复制到两个单独的文件中并单独运行,或者如果您有像eclipse这样的IDE,则可以从同一程序运行多个实例。上面显示的输出来自单个客户端程序,如果使用多个客户端,将获得类似的结果。

     
    转载请保留页面地址:https://www.breakyizhan.com/java/6603.html