基于TCP协议的Socket通信 JAVA多线程版(详细注释)

基于TCP协议的Socket通信 JAVA多线程版(详细注释),第1张

基于TCP协议的Socket通信 JAVA多线程版(详细注释)

文章目录
    • TCP连接流程
    • 代码实战
      • 1. 目录结构
      • 2. 代码详解
        • 客户端代码 Client.java
        • 服务端代码 Server.java
        • 服务端多线程代码 ServerThread.java
      • 3. 结果展示

TCP连接流程


整个的连接流程如图所示,需要注意的是服务器端创建了两个socket,一个用于监听,一个用于接受具体的连接,而本文所主要采用的多线程客户-服务器socket通信,主要是将连接成功的socket交给不同的线程去处理,来执行不同的数据传输任务(图中蓝色部分),从而服务器可以继续监听来自其他客户端的连接不被阻塞住。

代码实战 1. 目录结构

2. 代码详解 客户端代码 Client.java
package myTCP;
import java.net.Socket;
import java.net.UnknownHostException;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.BufferedReader;
public class Client {    
    public static void main(String[] args) {        
        try{    
                // 创建 socket 与 localhost:8888(服务器) 建立连接
                Socket socket = new Socket("localhost", 8888);
                

                //注意以上连接方式和流程图不符
                //我们没有绑定客户端的本地端口,如果我们想绑定可以按照如下方式:
                //Socket socket=new Socket();
                //socket.bind(new InetSocketAddress(3000)); // 绑定了本地的3000端口
                //socket.connect(new InetSocketAddress("localhost", 8888));

                // 获取socket输出流(这里的输出是相对与客户端的也就是会输出到服务器)
                OutputStream outStream = socket.getOutputStream();
                // PrintWriter 以便以我们可以传入更多类型的数据
                PrintWriter printWriter = new PrintWriter(outStream);
                // 要传输的内容
                printWriter.println("userName: zxd passWord: zxd");
                // 刷新缓冲区, 以免缓冲区残留数据
                printWriter.flush();
                // 关闭输出流,代表客户端向服务器传输数据结束
                socket.shutdownOutput();
                
                // 获取socket输入流(这里的输出是相对与客户端的也就是会会接受服务器的输出)
                InputStream is = socket.getInputStream();
                // InputStreamReader 使得我们可以按不同编码方式读取
                InputStreamReader isr = new InputStreamReader(is);
                // 读缓冲区
                BufferedReader br = new BufferedReader(isr);
                // 定义接收数据格式
                String data = null;
                // 按行接收并打印结果
                while ((data = br.readLine()) != null) {
                    System.out.println("服务器返回的数据为:"+data);
                }            
                // 收发数据均已经结束 关闭socket
                socket.close();
            // 以下是必须进行捕获的异常
            } catch (UnknownHostException e){
                e.printStackTrace();        
            } catch (IOException e) {
                e.printStackTrace();        
            }    
    }
}
服务端代码 Server.java
package myTCP;
import java.net.ServerSocket;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
public class Server {    
    public static void main(String[] args) {
        try {
            // 定义监听socket 监听8888端口
            ServerSocket serverSocket =  new ServerSocket(8888);
            // 定义连接socket
            Socket socket = null;
            // 记录客户端的连接次数
            int count = 0;
            // 此时服务器已经准备好 打印log
            System.out.println("Sever Start!!");
            // 循环监听
            while (true) {
                // 连接socket建立成功, 
                socket = serverSocket.accept();
                // 将具体的数据传输任务丢给连接处理线程 
                Thread thread = new Thread(new ServerThread(socket));
                // 线程开始运行
                thread.start();
                // 连接数加一
                count++;
                // 实时打印log 显示连接数
                System.out.println("The num of connection :" + count);
                // 获取连接地址
                InetAddress address = socket.getInetAddress();
                // 实时打印log 显示当前连接的客户端地址
                System.out.println("The address of client now:" + 
                address.getHostAddress());
            }
        // 服务器的连接不用关闭 
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
服务端多线程代码 ServerThread.java
package myTCP;
import java.net.Socket;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.IOException;
//  线程类实现runnable接口
public class ServerThread implements Runnable{
    // 对应连接socket
    Socket socket = null;
    // 构造函数初始化连接socket
    public ServerThread(Socket socket){
        this.socket = socket;
    }
    public void run(){
        // 与客户端一样定义一系列输入输出流和缓冲区
        InputStream is = null;
        InputStreamReader isr = null;
        BufferedReader br = null;
        OutputStream os = null;
        PrintWriter pw = null;
        try{
            // 获取客户端的输入
            is = socket.getInputStream();
            isr = new InputStreamReader(is);
            br = new BufferedReader(isr);
            // 定义接收数据
            String data = null;
            
            // 按行接收,并返回数据给客户端
            while((data = br.readLine()) != null) {
                System.out.println("The client seed data:" + data);
                os = socket.getOutputStream();
                pw = new PrintWriter(os);
                pw.println("Access tcpServer Successfully!");
                pw.flush();
            }
        // 必须进行的异常捕获
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 按顺序关闭缓冲区和流(先开后关)
            try {
                if (pw != null) {
                pw.close();
                }
                if (os != null) {
                os.close();
                }
                if (br != null) {
                br.close();
                }
                if (isr != null) {
                isr.close();
                }
                if (is != null) {
                is.close();
                }
                if (socket!= null) {
                socket.close();
                }
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
3. 结果展示
  • 先运行Server.java 文件

  • 在运行客户端文件

  • 此时服务端会打印log

  • 保持服务端开启,再次运行客户端程序

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5596005.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-15
下一篇 2022-12-15

发表评论

登录后才能评论

评论列表(0条)

保存