Java学习总结:52(Java网络编程)

Java网络编程

开发第一个网络程序

java.net包提供了网络编程有关的开发工具类,在此包中有一下两个主要的核心操作类。

  • ServerSocket类:是一个封装支持的TCP协议的操作类,主要工作在服务器端,用于接收客户端请求;
  • Socket类:也是一个封装了TCP协议的操作类,每一个Socket对象都表示一个客户端。

ServerSocket类的常用方法

No. 方法名称 类型 描述
1 public ServerSocket(int port) throws IOException 构造 开辟一个指定的端口监听,一般使用5000以上的端口
2 public Socket accept() throws IOException 普通 服务器端接收客户端请求,通过Socket返回
3 public void close() throws IOException 普通 关闭服务器端

Socket类的常用方法

No. 方法名称 类型 描述
1 public Socket(String host, int port) throws UnknownHostException,IOException 构造 指定要连接的主机(IP地址)和接口,host代表主机的IP地址,如果是本机直接访问,则使用localhost(127.0.0.1)代替IP
2 public OutputStream getOutputStream() throws IOException 普通 取得指定客户端的输出对象,使用PrintStream操作
3 public InputStream getInputStream() throws IOException 普通 从指定的客户端读取数据,使用Scanner操作

在客户端,程序可以通过Socket类的getInputStream()方法,取得服务器的输出信息,在服务器端可以通过getOutputStream()方法取得客户端的输出信息。

例:定义服务器端

package Project.Study.ServerSocket;

import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Test1 {
    public static void main(String[]args)throws Exception{
        ServerSocket server = new ServerSocket(9999);   //所有的服务器必须有接口
        System.out.println("等待客户端连接...");
        Socket socket = server.accept();                      //等待客户端连接
        //OutputStream并不方便进行内容的输出,所以利用打印流完成输出
        PrintStream out = new PrintStream(socket.getOutputStream());
        out.println("Hello World!!!");                          //输出数据
        out.close();
        socket.close();
        server.close();
    }
}
//结果:
//等待客户端连接...(此处讲出现堵塞情况,一直到客户端连接后才会继续执行)

本程序在本机的9999端口上设置了一个服务器的监听操作(accept()方法表示打开服务器监听),这样当有客户端通过TCP连接方式连接到服务器端后,服务器端将利用PrintStream输出数据,当数据输出完毕后该服务器就将关闭,所以本次定义的服务器只能处理一次客户端的请求。

例:编写客户端

package Project.Study.Socket;

import java.net.Socket;
import java.util.Scanner;

public class Test1 {
    public static void main(String[]args)throws Exception{
        Socket socket = new Socket("localhost",9999);//连接服务器
        //取得客户端的输入数据流对象,表示接收服务器端的输出信息
        Scanner scanner = new Scanner(socket.getInputStream());
        scanner.useDelimiter("\n");     //设置分隔符
        if (scanner.hasNext()){         //判断是否有数据
            System.out.println("回应数据:"+scanner.next());//取出数据
        }
        scanner.close();
        socket.close();
    }
}
//结果:
//回应数据:Hello World!!!

在TCP程序中,每一个Socket对象都表示一个客户端的信息,所以客户端程序要连接也必须依靠Socket对象操作。在实例化Socket类对象时必须设置要连接的主机名称(本机为localhost,或者填写IP地址)以及连接端口号,当连接成功后就可以利用Scanner进行输入流数据的读取,接收服务器端的回应信息。

网络开发的经典模型——Echo程序

例:实现服务器端

package Project.Study.ServerSocket;

import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

public class Test2 {
    public static void main(String[]args)throws Exception{
        ServerSocket serverSocket = new ServerSocket(9999);     //定义连接端口
        Socket socket = serverSocket.accept();                          //等待客户连接
        //得到客户端输入的数据以及向客户端输出数据的对象,利用扫描流接收,打印流输出
        Scanner scanner = new Scanner(socket.getInputStream());
        PrintStream out = new PrintStream(socket.getOutputStream());
        boolean flag = true;                                            //设置循环标记
        while (flag){
            if (scanner.hasNext()){                                     //是否有内容输入
                String str = scanner.next().trim();                     //得到客户端发送的内容,并删除空格
                if (str.equalsIgnoreCase("####")){          //程序结束标记
                    out.println("再见!");                                 //输出结束信息
                    flag = false;                                           //退出循环
                }else{                                                  //回应输入信息
                    out.println("ECHO:"+str);                           //加上前缀返回
                }
            }
        }
        scanner.close();
        out.close();
        socket.close();
        serverSocket.close();
    }
}

该服务器端存在一个缺陷,它是单线程的网络应用,所有的操作都是在主线程上进行的开发,所以只能连接一个客户端,不能连接其他客户端。

例:修改服务器端(使其可以同时处理多个客户端的连接操作)

package Project.Study.ServerSocket;

import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

class EchoThread implements Runnable{   //建立线程类
    private Socket socket;              //每个线程处理一个客户端
    public EchoThread(Socket socket){   //创建线程对象时传递Socket
        this.socket=socket;
    }
    @Override
    public void run(){
        try {                           //每个线程对象取得各自Socket的输入流与输出流
            Scanner scanner = new Scanner(socket.getInputStream());
            PrintStream out = new PrintStream(socket.getOutputStream());
            boolean flag = true;                            //控制多次接收操作
            while (flag){
                if (scanner.hasNext()){                     //判断是否有内容
                    String str = scanner.next().trim();     //得到客户端发送的内容
                    if (str.equalsIgnoreCase("###")){//程序结束
                        out.println("再见!");
                        flag = false;                       //退出循环
                    }else{                                  //应该回应输入信息
                        out.println("ECHO:"+str);           //回应信息
                    }
                }
            }
            scanner.close();
            out.close();
            socket.close();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}
public class Test3 {
    public static void main(String[]args)throws Exception{
        ServerSocket serverSocket = new ServerSocket(9999);//在9999端口上监听
        boolean flag = true;                                    //循环标记
        while (flag){                                           //接收多个客户端请求
            Socket socket = serverSocket.accept();              //客户端连接
            new Thread(new EchoThread(socket)).start();         //创建并启动新线程
        }
        serverSocket.close();
    }
}

例:定义客户端

package Project.Study.Socket;

import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;

public class Test2 {
    public static void main(String[]args)throws Exception{
        Socket socket = new Socket("localhost",9999);   //服务器地址和端口
        Scanner input = new Scanner(System.in);                     //键盘输入数据
        //利用Scanner包装客户端输入数据(服务器端输出),PrintStream包装客户端输出数据
        Scanner scanner = new Scanner(socket.getInputStream());
        PrintStream out = new PrintStream(socket.getOutputStream());
        input.useDelimiter("\n");                                   //设置键盘输入分隔符
        scanner.useDelimiter("\n");                                 //设置回应数据分隔符
        boolean flag = true;                                        //循环标志
        while (flag){
            System.out.println("请输入要发送的数据:");
            if (input.hasNext()){                                   //判断键盘是否输入数据
                String str = input.next().trim();                   //取得键盘输入的数据
                out.println(str);                                   //发送数据到服务器端
                if (str.equalsIgnoreCase("###")){       //结束标记
                    flag = false;                                       //结束循环
                }
                if (scanner.hasNext()){                             //服务器有回应
                    System.out.println(scanner.next());             //输出回应数据
                }
            }
        }
        input.close();
        scanner.close();
        out.close();
        socket.close();
    }
}

结果博主就不发了,自己在两个端口自问自答感觉有点怪。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章