Java Socket编程中的线程入门
Socket编程在网络上的两台计算机之间建立了通信。套接字通信使用了两种协议。
- 用户数据报协议(UDP)。这是一个无连接协议。它主要用于在两个节点之间建立一个低延迟的连接。
- 传输控制协议(TCP)。这是一个面向连接的协议。它用于在两个节点之间建立连接。
前提条件
要跟上时代的步伐,读者需要熟悉以下内容。
- Java编程语言。
- 安装一个你选择的代码编辑器。
线程
线程允许程序通过同时做多件事情来更有效地运行。Java.lang ,负责制作和管理线程的Java.Class 。
为什么线程
服务器能够同时处理多个客户端也是至关重要的。具备同时管理多个消费者的能力是我们设计框架的一个要求。我们的服务器端架构需要线程,以便在每个请求到达时将其分配给一个数据输入流线程。
要创建一个新的Java线程,就必须。
- 实现
Runnable接口。这可以通过运行java.lang.Runnable。 - 通过运行
java.lang.Thread来扩展Thread类。
服务器端编程
下面是我们将需要的类。
服务器类
客户端的构建应从服务器的流和端口号的集合开始,然后进行以下步骤。
- 一个while循环将建立套接字对象,接收来自服务器套接字对象的连接。
- 我们将把请求的流纳入当前的套接字中。
- 客户端处理程序对象是由类从流和端口号中创建的。
- 启动程序将调用
start()方法。这个新线程对象的start()函数必须被调用以开始运行。
ClientHandler类
线程的属性被传递给基于框架的客户处理程序类。该类的构造函数需要三个参数。Socket,DataInputStream, 和DataOutputStream 。服务器在创建Thread时得到它的端口号以及数据输入和输出流对象。
Java服务器端软件包括Server 和ClientHandler 类。
- 创建一个名为
Serverclass的新的Java类,并用下面的代码片断来更新它。
import java.io.*;
import java.text.*;
import java.util.*;
import java.net.*;
public class Serverclass
{
public static void main(String[] args) throws IOException
{
ServerSocket myserverSocket = new ServerSocket(5056);
// getting client request
while (true)
// running infinite loop
{
Socket mynewSocket = null;
try
{
// mynewSocket object to receive incoming client requests
mynewSocket = myserverSocket.accept();
System.out.println("A new connection identified : " + mynewSocket);
// obtaining input and out streams
DataInputStream ournewDataInputstream = new DataInputStream(mynewSocket.getInputStream());
DataOutputStream ournewDataOutputstream = new DataOutputStream(mynewSocket.getOutputStream());
System.out.println("Thread assigned");
Thread myThread = new ClientHandler(mynewSocket, ournewDataInputstream, ournewDataOutputstream);
// starting
myThread.start();
}
catch (Exception e){
mynewSocket.close();
e.printStackTrace();
}
}
}
}
- 创建一个新的Java类,命名为
ClientHandler,并用下面的代码片断进行更新。
class ClientHandler extends Thread
{
DateFormat forourdate = new SimpleDateFormat("yyyy/MM/dd");
DateFormat forourtime = new SimpleDateFormat("hh:mm:myserverSocket");
final DataInputStream ournewDataInputstream;
final DataOutputStream ournewDataOutputstream;
final Socket mynewSocket;
// Constructor
public ClientHandler(Socket mynewSocket, DataInputStream ournewDataInputstream, DataOutputStream ournewDataOutputstream)
{
this.mynewSocket = mynewSocket;
this.ournewDataInputstream = ournewDataInputstream;
this.ournewDataOutputstream = ournewDataOutputstream;
}
@Override
public void run()
{
String receivedString;
String stringToReturn;
while (true)
{
try {
ournewDataOutputstream.writeUTF("Choose: [Date | Time]..\n"+
"Or Exit");
// getting answers from client
receivedString = ournewDataInputstream.readUTF();
if(receivedString.equals("Exit"))
{
System.out.println("Client " + this.mynewSocket + " sends exit...");
System.out.println("Connection closing...");
this.mynewSocket.close();
System.out.println("Closed");
break;
}
// creating Date object
Date mynewDate = new Date();
switch (receivedString) {
case "Date" :
stringToReturn = forourdate.format(mynewDate);
ournewDataOutputstream.writeUTF(stringToReturn);
break;
case "Time" :
stringToReturn = forourtime.format(mynewDate);
ournewDataOutputstream.writeUTF(stringToReturn);
break;
default:
ournewDataOutputstream.writeUTF("Invalid input");
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
try
{
// closing resources
this.ournewDataInputstream.close();
this.ournewDataOutputstream.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
- 运行
Serverclass中的main方法。
输出。
A new connection identified : Socket[addr=/127.0.0.1,port=60536,localport=5056]
Thread assigned
Client Socket[addr=/127.0.0.1,port=60536,localport=5056] sends exit...
Connection closing...
Closed
客户端编程
客户端编程和传统的套接字编程之间有许多相似之处,其中包括。
- 建立一个套接字连接。
- 通信。
- 创建一个新的Java类,命名为
NewClient,并用下面的代码片断来更新它。
import java.util.Scanner;
import java.io.*;
import java.net.*;
public class NewClient
{
public static void main(String[] args) throws IOException
{
try
{
Scanner ourNewscanner = new Scanner(System.in);
InetAddress inetadress = InetAddress.getByName("localhost");
// establishing the connection
Socket ournewsocket = new Socket(inetadress, 3333);
DataInputStream ournewDataInputstream = new DataInputStream(ournewsocket.getInputStream());
DataOutputStream ournewDataOutputstream = new DataOutputStream(ournewsocket.getOutputStream());
// In the following loop, the client and client handle exchange data.
while (true)
{
System.out.println(ournewDataInputstream.readUTF());
String tosend = ourNewscanner.nextLine();
ournewDataOutputstream.writeUTF(tosend);
// Exiting from a while loo should be done when a client gives an exit message.
if(tosend.equals("Exit"))
{
System.out.println("Connection closing... : " + ournewsocket);
ournewsocket.close();
System.out.println("Closed");
break;
}
// printing date or time as requested by client
String newresuiltReceivedString = ournewDataInputstream.readUTF();
System.out.println(newresuiltReceivedString);
}
ourNewscanner.close();
ournewDataInputstream.close();
ournewDataOutputstream.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
- 运行上面
NewClient类中的main方法。
输出。
Choose[Date | Time]..
Or Exit
Date
2017/06/16
Choose[Date | Time]..
Or Exit
Time
05:35:28
Choose[Date | Time]..
Or Exit
Exit
Connection closing... : Socket[addr=localhost/127.0.0.1,port=5056,localport=60536]
Closed
- 每次客户端请求连接到服务器时,都会创建一个新的线程。
- 新线程一旦被分配,就会获得对所有可用流的访问。当服务器被分配时,它将接受这个请求。
- 直到第一个请求完成后,服务器接受并处理第二个请求。
测试程序
一个接一个地运行Server.java 和Client.java 。要同时执行客户端程序的众多实例,请利用类似多实例的IDE,或在不同的文件中运行客户端软件。为了得到上面显示的结果数据输入流,你将需要无数个客户端。
总结
这篇文章涵盖了套接字编程、Thread 及其使用、服务器端编程和客户端编程。
我们的实现显示了线程在Java中的重要性,在Java套接字编程中加强和理解线程。