← 返回首页
JavaSE系列教程(一百零二)
发表时间:2021-12-14 11:02:53
TCP

Socket通信本质就是两个进程之间的通信。

1.socket编程

为什么需要Socket进行网络通信?因为仅仅通过IP地址进行通信是不够的,同一台计算机同一时间会运行多个网络应用程序,例如浏览器、QQ、邮件客户端等。当操作系统接收到一个数据包的时候,如果只有IP地址,它没法判断应该发给哪个应用程序,所以,操作系统抽象出Socket接口,每个应用程序需要各自对应到不同的Socket,数据包才能根据Socket正确地发到对应的应用程序。

一个Socket就是由IP地址和端口号(范围是0~65535)组成,可以把Socket简单理解为IP地址加端口号。端口号总是由操作系统分配,它是一个0~65535之间的数字,其中,小于1024的端口属于特权端口,需要管理员权限,大于1024的端口可以由任意用户的应用程序打开。

java.net.Socket 类代表一个套接字,并且 java.net.ServerSocket 类为服务器程序提供了一种来监听客户端,并与他们建立连接的机制。

服务器与客户端之间使用Socket通信的基本步骤如下:

TCP 是一个双向的通信协议,因此数据可以通过两个数据流在同一时间发送.以下是一些类提供的一套完整的有用的方法来实现 socket。

2.TCP实现socket通信

实例:

实现一个服务器与多个客户端的TCP通信。

MyServer.java


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

public class MyServer implements Runnable {

    private Socket client; //客户端的连接对象。

    public MyServer(Socket client) {
        this.client = client;
    }

    @Override
    public void run() {
        //输入流:负责获得客户端发来的消息。
        BufferedReader input = null;
        //输入流:负责从控制台获得用户输入的字符串。
        BufferedReader in = null;
        //输出流:负责给客户端发消息。(因为给屏幕输出,所以应该使用PrintStream)
        PrintStream output = null;
        boolean flag = true;
        try {
            //InputStreamReader字节流转换为字符流
            input = new BufferedReader(new InputStreamReader(client.getInputStream()));
            in = new BufferedReader(new InputStreamReader(System.in));
            output = new PrintStream(client.getOutputStream());

            while (flag) {
                //获得客户端发来的字符串
                String msg = input.readLine();
                //这三种情况,都认为是结束线程
                if (msg == null || "".equals(msg) || "bye".equals(msg)) {
                    flag = false;
                } else {
                    System.out.println(msg);
                    //发送消息给客户端
                    System.out.println("请输入内容:");
                    msg = in.readLine();
                    if (msg == null || "".equals(msg) || "bye".equals(msg)) {
                        flag = false;
                    } else {
                        output.println("服务器:" + msg);
                    }
                }
            }
            input.close();
            output.close();
            client.close();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    public static void main(String[] args) {
        //创建一个ServerSocket.
        boolean flag = true;
        ServerSocket server = null;
        try {
            //启动服务
            server = new ServerSocket(9999);
            //接收客户端的请求,是阻塞方法
            while (flag) {
                System.out.println("服务器已经启动,等待客户端的请求....");
                Socket client = server.accept();
                //开启一个线程和客户端聊天
                new Thread(new MyServer(client)).start();  //创建了一个服务器对象启动一个线程
            }
            System.out.println("服务器已经关闭....");
            server.close();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

MyClient.java


import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;

public class MyClient {

    public static void main(String[] args) {
        Socket client = null;
        boolean flag = true;

        //输入流:负责获得客户端发来的消息。
        BufferedReader input = null;
        //输入流:负责从控制台获得用户输入的字符串。
        BufferedReader in = null;
        //输出流:负责给客户端发消息。(因为给屏幕输出,所以应该使用PrintStream)
        PrintStream output = null;
        try {
            //首先连接服务器
            client = new Socket("localhost", 9999);
            input = new BufferedReader(new InputStreamReader(client.getInputStream()));
            in = new BufferedReader(new InputStreamReader(System.in));
            output = new PrintStream(client.getOutputStream());

            while (flag) {
                //首先给服务发送消息
                System.out.println("请输入内容:");
                String msg = in.readLine();
                if (msg == null || "".equals(msg) || "bye".equals(msg)) {
                    flag = false;
                    //最后这个'bye'必须发送给服务器
                    output.println(msg);
                } else {
                    output.println("客户端:" + msg);
                    //获得服务发来的消息
                    msg = input.readLine();
                    if (msg == null || "".equals(msg) || "bye".equals(msg)) {
                        flag = false;
                    } else {
                        System.out.println(msg);
                    }
                }
            }
            input.close();
            in.close();
            output.close();
            client.close();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

先启动服务器,再启动两个客户端。 运行结果如下:

服务器控制台

服务器已经启动,等待客户端的请求....
服务器已经启动,等待客户端的请求....
服务器已经启动,等待客户端的请求....
客户端:你好,我是张三
请输入内容:
你好,我是服务器
客户端:你好,我是李四
请输入内容:
你好,我是服务器

客户端1

请输入内容:
你好,我是李四
服务器:你好,我是服务器
请输入内容:
bye

客户端2

请输入内容:
你好,我是张三
服务器:你好,我是服务器
请输入内容:
bye