1.InetAddress类
1.1 InetAddress类的作用
服务器程序可以使用InetAddress类来获得对方端的IP地址和主机名字等信息。
在服务器程序中使用下面的语句可以得到与客户端相连的套接字上的一个InetAddress实例并使用相应的方法显示客户端的主机名和IP地址:
public static void main(String[] args) {
try{
//创建套接字
Socket socket = new Socket("www.baidu.com",80);
InetAddress inetAddress = socket.getInetAddress();
System.out.println("Server's host name is: "+inetAddress.getHostName());
System.out.println("Server's IP Address name is: "+inetAddress.getHostAddress());
}catch(IOException ex) {
ex.printStackTrace();
}
}
除此之外,还可以使用静态方法getByName通过主机名或IP地址创建一个InetAddress的实例。
例如下面语句为主机liang.armstrong.edu创建一个InetAddress实例:
InetAddress address = InetAddress.getByName("www.baidu.com");
public static void main(String[] args) {
try{
//创建套接字
Socket socket = new Socket("www.baidu.com",80);
InetAddress inetAddress = socket.getInetAddress();
System.out.println("Server's host name is: "+inetAddress.getHostName());
System.out.println("Server's IP Address name is: "+inetAddress.getHostAddress());
InetAddress address = InetAddress.getByName("www.baidu.com");
System.out.println("Server's host name is: "+address.getHostName());
System.out.println("Server's IP Address name is: "+address.getHostAddress());
}catch(IOException ex) {
ex.printStackTrace();
}
}
2.服务多个用户
我们可以使用线程处理服务器上多个客户端的同时访问。
可以简单地为每个连接创建一个线程,下面给出服务器如何处理连接:
while(true){
Socket socket = serverSocket.accept();
Thread thread = new ThreadClass(socket);//为连接创建线程
thread.start();//线程开始
}
while循环的每次迭代监听成功后创建一个新连接和新线程。
2.2 多线程服务器例子学习
2.2.1 带UI版
Server.java
package Progress.exa29_2.part2.ui;
import java.io.*;
import java.net.*;
import java.util.Date;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextArea;
import javafx.stage.Stage;
public class Server extends Application {
private TextArea textArea = new TextArea();
private int clientNo = 0;
public void start(Stage primaryStage) {
Scene scene=new Scene(new ScrollPane(textArea),450,200);
primaryStage.setTitle("Server");
primaryStage.setScene(scene);
primaryStage.show();
/*
建立一个线程创建服务器实例并启动监听
*/
new Thread(()->{
try{
//创建服务器套接字,服务器端口号设为8000
ServerSocket serverSocket = new ServerSocket(8000);
Platform.runLater(()->textArea.appendText("Server started at"+new Date()+'\n'));
//进入无线循环
while(true){
//服务器进入监听状态
Socket socket = serverSocket.accept();
//有客户端连接服务端,客户数加一
clientNo++;
Platform.runLater(()->{
textArea.appendText("客户端连接数: "+clientNo+" "+new Date()+'\n');
InetAddress inetAddress = socket.getInetAddress();
textArea.appendText("客户端 "+clientNo+" 号 的主机名为: "+inetAddress.getHostName()+'\n');
textArea.appendText("客户端 "+clientNo+"号的IP地址为: "+inetAddress.getHostAddress()+'\n');
});
//为客户端创建新线程进行持续交互
new Thread(new HandleAClient(socket)).start();
}
}catch(IOException ex){
ex.printStackTrace();
}
}).start();
}
/**
* 持续交互任务定义
*/
class HandleAClient implements Runnable{
//此任务的客户端套接字
private Socket socket;
public HandleAClient(Socket socket) {
this.socket=socket;
}
public void run() {
try{
//创建服务器接受和发送数据的流
DataInputStream inputFromClient=new DataInputStream(socket.getInputStream());
DataOutputStream outputToClient = new DataOutputStream(socket.getOutputStream());
//持续监听客户端发送的数据
while(true) {
double radius = inputFromClient.readDouble();
double area=radius*radius*Math.PI;
outputToClient.writeDouble(area);
Platform.runLater(()->{
textArea.appendText("得到客户端的半径数据: "+radius+'\n');
textArea.appendText("计算出来的面积为: "+area+'\n');
});
}
}catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
Client.java
package Progress.exa29_2.part2.ui;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
public class Client extends Application {
DataOutputStream toServer=null;//声明输出流
DataInputStream fromServer=null;//声明输入流
public void start(Stage primaryStage) {
BorderPane paneForTextField=new BorderPane();
paneForTextField.setPadding(new Insets(5,5,5,5));
paneForTextField.setStyle("-fx-border-color:green");
paneForTextField.setLeft(new Label("输入一个半径: "));
TextField tf=new TextField();
tf.setAlignment(Pos.BOTTOM_RIGHT);
paneForTextField.setCenter(tf);
BorderPane mainPane = new BorderPane();
TextArea ta = new TextArea();
mainPane.setCenter(new ScrollPane(ta));
mainPane.setTop(paneForTextField);
Scene scene=new Scene(mainPane,450,200);
primaryStage.setTitle("Client");
primaryStage.setScene(scene);
primaryStage.show();
tf.setOnAction(e->{
try{
double radius = Double.parseDouble(tf.getText().trim());
toServer.writeDouble(radius);//将radius写入输出流
toServer.flush();//清空输出流
//从输入流中获取的值赋给area,此方法会阻塞,知道服务器传数据过来
double area = fromServer.readDouble();
ta.appendText("半径是: "+radius+'\n');
ta.appendText("服务器返回的面积为: "+area+'\n');
}catch (IOException ex) {
System.err.println(ex);
}
});
try{
//创建套接字
Socket socket = new Socket("localhost",8000);
//创建客户端接受和发送数据的流
fromServer=new DataInputStream(socket.getInputStream());
toServer = new DataOutputStream(socket.getOutputStream());
}catch(IOException ex) {
ta.appendText(ex.toString()+'\n');
}
}
}
2.2.2 无UI版
Server.java
package Progress.exa29_2.part2.noUi;
import javafx.application.Platform;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;
public class NoUIServer {
private static int clientNo = 0;
public static void main(String[] args) {
/*
建立一个线程创建服务器实例并启动监听
*/
new Thread(()->{
try{
//创建服务器套接字,服务器端口号设为8000
ServerSocket serverSocket = new ServerSocket(8000);
System.out.println(("Server started at"+new Date()+'\n'));
//进入无线循环
while(true){
//服务器进入监听状态
Socket socket = serverSocket.accept();
//有客户端连接服务端,客户数加一
clientNo++;
System.out.println("客户端连接数: "+clientNo+" "+new Date()+'\n');
InetAddress inetAddress = socket.getInetAddress();
System.out.println("客户端 "+clientNo+" 号 的主机名为: "+inetAddress.getHostName()+'\n');
System.out.println("客户端 "+clientNo+"号的IP地址为: "+inetAddress.getHostAddress()+'\n');
//为客户端创建新线程进行持续交互
new Thread(new HandleAClient(socket)).start();
}
}catch(IOException ex){
ex.printStackTrace();
}
}).start();
}
}
/**
* 持续交互任务定义
*/
class HandleAClient implements Runnable{
//此任务的客户端套接字
private Socket socket;
public HandleAClient(Socket socket) {
this.socket=socket;
}
public void run() {
try{
//创建服务器接受和发送数据的流
DataInputStream inputFromClient=new DataInputStream(socket.getInputStream());
DataOutputStream outputToClient = new DataOutputStream(socket.getOutputStream());
//持续监听客户端发送的数据
while(true) {
double radius = inputFromClient.readDouble();
double area=radius*radius*Math.PI;
outputToClient.writeDouble(area);
System.out.println("得到客户端的半径数据: "+radius+'\n');
System.out.println("计算出来的面积为: "+area+'\n');
}
}catch (IOException ex) {
ex.printStackTrace();
}
}
}
Client.java
package Progress.exa29_2.part2.noUi;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.Scanner;
public class NoUIClient {
public static void main(String[] args) {
DataOutputStream toServer=null;//声明输出流
DataInputStream fromServer=null;//声明输入流
try{
//创建套接字
Socket socket = new Socket("localhost",8000);
//创建客户端接受和发送数据的流
fromServer=new DataInputStream(socket.getInputStream());
toServer = new DataOutputStream(socket.getOutputStream());
while (true){
System.out.println("请输入半径:");
Scanner sc = new Scanner(System.in);
double radius = sc.nextDouble();
//将radius写入输出流发送出去
toServer.writeDouble(radius);
toServer.flush();//清空输出流
//从输入流中获取的值赋给area(此方法会阻塞)
double area = fromServer.readDouble();
System.out.println("半径:"+radius+'\n');
System.out.println("面积是: "+area+'\n');
}
}catch(IOException ex) {
System.out.println(ex.toString()+'\n');
}
}
}
3.代码地址
Java基础学习/src/main/java/Progress/exa29_2 · 严家豆/Study - 码云 - 开源中国 (gitee.com)