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

作者: Arvin Chen 分类: Java 来源: Break易站(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,则可以从同一程序运行多个实例。上面显示的输出来自单个客户端程序,如果使用多个客户端,将获得类似的结果。

  •   本文标题:在Java中使用Socket套接字编程引入多线程 - Break易站
    转载请保留页面地址:https://www.breakyizhan.com/java/6603.html

    发表笔记

    电子邮件地址不会被公开。 必填项已用*标注

    更多阅读