29.2 Java进阶之网络InetAddress类,多线程网络编程

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)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员小牧之

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值