- TCP连接流程
- 代码实战
- 1. 目录结构
- 2. 代码详解
- 客户端代码 Client.java
- 服务端代码 Server.java
- 服务端多线程代码 ServerThread.java
- 3. 结果展示
整个的连接流程如图所示,需要注意的是服务器端创建了两个socket,一个用于监听,一个用于接受具体的连接,而本文所主要采用的多线程客户-服务器socket通信,主要是将连接成功的socket交给不同的线程去处理,来执行不同的数据传输任务(图中蓝色部分),从而服务器可以继续监听来自其他客户端的连接不被阻塞住。
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
-
保持服务端开启,再次运行客户端程序
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)