[Java网络编程二]编写基于TCP的Socket程序

读书百遍,其义自现。(三国志)
它的意思是读书一百遍,其中的意义和思想就自然显露出来了。

我们知道,在 Java 提供的网络库中,提供了三种套接字类:java.net.Socket, java.net.ServerSocket,DatagramSocket。其中,Socket 和 ServerSocket 是建立在 TCP 协议的基础上,DatagramSocket 建立在 UDP 协议的基础上。

传输层向应用层提供了套接字 Socket 接口,Socket 封装了下层的数据传输细节,应用层的程序通过调用 Socket Api 来建立与远程主机连接,进行出具传输. 流程如下图所示:
[Java网络编程二]编写基于TCP的Socket程序_第1张图片

创建服务端程序 TcpServer

① ServerSocket 构造方法负责在操作系统中把当前进程注册为服务器进程,传入要监听的端口。
② 接着调用 accept() 函数一直监听端口,等待客户的连接请求。如果收到一个连接请求,它就返回一个 Socket 对象。这个Socket 对象和客户端的 Socket 形成了一条通信链路。
③ 通过 Socket 提供的 getInputStream() 和 getOutputStream() 方法,分别返回输入流 InputStream 对象和输出流 OutputStream 对象。向输出流写数据,就能向对方发送数据。从输入流读数据,就能接收来自客户端的数据。
④ 把 Socket 的输入输出流用过滤流来装饰。用 PrintWriter 装饰输出流,调用它的 println() 能够写一行数据。用 BufferedReader 装饰输入流,调用它的 readLine() 读入一行数据。

源代码如下:

import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

class TcpServer {

    private static final int PORT = 8000; //端口
    private ServerSocket serverSocket;

    //构造函数,创建 ServerSocket 对象
    public TcpServer() throws IOException {
        serverSocket = new ServerSocket(PORT);
        System.out.println("服务器启动啦");
    }

    //获取输出流
    private PrintWriter getWriter(Socket socket) throws IOException {
        OutputStream socketOut = socket.getOutputStream();
        return new PrintWriter(socketOut, true);
    }

    //获取输入流
    private BufferedReader getReader(Socket socket) throws IOException {
        InputStream socketIn = socket.getInputStream();
        return new BufferedReader(new InputStreamReader(socketIn));
    }

    public void start(){
        //不断监听
        while(true){
            Socket socket = null;
            try {
                socket = serverSocket.accept(); //监听是否有客户端连接

                //连接成功,打印连接的客户端信息
                System.out.println("客户端已连接,ip = " + socket.getInetAddress() + "port = " + socket.getPort());

                BufferedReader br = getReader(socket);//获取输入流
                PrintWriter pr = getWriter(socket);//获取输出流

                String msg = null;

                //不断读取客户端发过来的信息
                while((msg = br.readLine())!= null){
                    System.out.println(msg);
                    pr.println("server receive: " + msg); //发消息给客户端,告诉他收到了消息
                    if(msg.equals("bye")){
                        break;
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                if(socket != null){
                    try {
                        socket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    public static void main(String[] args) throws IOException {
        new TcpServer().start();
    }
}

执行结果如下:
① ip 地址,这里为本机地址。
② port 为系统随机分配给客户端的,每次客户端连接都会重新分配端口,每次基本都是不同的。
③ 结合客户端端的执行结果来看。
[Java网络编程二]编写基于TCP的Socket程序_第2张图片

创建客户端程序 TcpClient

① 首先,创建一个 Socket 对象,参数为主机地址和端口。此例子客户端进程和服务端进程都运行在同一个主机上,所以地址直接用“localhost”。
② 对象创建成功表示连接成功,接着从 Socket 对象获取输入输出流,另外,创建一个线程用于读取服务端发过来的数据,这样两者zh就可以进行通信发送数据了。
源代码如下所示:

import java.io.*;
import java.net.Socket;

public class TcpClient {

    private static final int PORT = 8000;//服务端端口
    private Socket socket;
    private static final String host = "localhost";//本地地址,127.0.0.1

    //构造函数
    public TcpClient() throws IOException {
        socket = new Socket(host, PORT);
        System.out.println("开始连接服务端");
    }

    //获取输出流
    private PrintWriter getWriter(Socket socket) throws IOException {
        OutputStream socketOut = socket.getOutputStream();
        return new PrintWriter(socketOut, true);
    }

    //获取输入流
    private BufferedReader getReader(Socket socket) throws IOException {
        InputStream socketIn = socket.getInputStream();
        return new BufferedReader(new InputStreamReader(socketIn));
    }

    //开始通信
    public void start() throws IOException {
        try {
            BufferedReader br = getReader(socket);//获取输入流
            PrintWriter pw = getWriter(socket);//获取输出流

            //读取我们的键盘输入
            BufferedReader localReaer = new BufferedReader(new InputStreamReader(System.in));

            String msg = null;

            //启动一个线程用于读取服务端消息
            new Thread(new ReceiveRunnable(br)).start();

            //不断读取键盘输入
            while ((msg = localReaer.readLine()) != null) {
                pw.println(msg);//发送给服务端
                if (msg.equals("bye")) {
                    break;
                }
            }
            System.out.println("end");
        } finally {
            socket.close();
        }
    }

    public static void main(String[] args) throws IOException {
        new TcpClient().start();
        System.out.println("客户端退出");
    }

    class ReceiveRunnable implements Runnable{
        private BufferedReader br;
        public ReceiveRunnable(BufferedReader br) {
            this.br = br;
        }

        @Override
        public void run() {
            String msg;
            try{
                //读取服务端发送过来的数据
                while(null != (msg = br.readLine())){
                    System.out.println(msg);
                }
            } catch (IOException E){
            } finally {
            }
        }
    }
}

执行结果如下:
① 发送数据 456 给服务器,并接收的服务端发回来的数据 server receive:456。
② 以此类推,最后 发送 bye ,让客户端退出,结束。
[Java网络编程二]编写基于TCP的Socket程序_第3张图片

你可能感兴趣的:([Java网络编程二]编写基于TCP的Socket程序)