Java网络编程之(二): TCP的多线程连接
相比前面一个例子,这里加入了多线程的操作,服务器可以不断读取客户端数据,并向客户端写入数据;客户端也可以不断的读取服务器数据,并向服务器写入数据。支持多客户端,功能实际就是一个基于Socket的TCP简易聊天程序,服务端实现了消息的转发。
局域网中电脑A用作服务端,IP为192.168,31.168
同时电脑A中开启另一个终端作为一个客户端
电脑B用作客户端,IP为192.168.31.132
一. TcpServer_2.java
import java.net.ServerSocket; import java.io.IOException; import java.net.Socket; import java.util.ArrayList; public class TcpServer_2 { //定义保存所有Socket的ArrayList public static ArrayList<Socket> socketList = new ArrayList<Socket>(); public static void main(String[] args)throws IOException { ServerSocket ss = new ServerSocket(30001); while(true) { //此行代码会阻塞,将一直等待别人的连接 Socket s = ss.accept(); socketList.add(s); //每当客户端连接后,启动一条ServerThread线程为该客户端服务 new Thread(new ServerThread(s)).start(); } } }
二. ServerThread.java
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.Socket; //负责处理每个线程通信的线程类 public class ServerThread implements Runnable { //定义当前线程所处理的Scoket Socket s = null; //该线程所处理的Socket所对应的输入流 BufferedReader br = null; public ServerThread(Socket s) throws IOException { this.s = s; //初始化该Socket对应的输入流 br = new BufferedReader(new InputStreamReader(s.getInputStream())); } public void run() { try { String connect = null; //采用循环不断从Socket中读取客户端送过来的数据 while((connect = readFromClient()) != null) { //遍历socketList中的每个Socket,将读到的内容向每个Socket发送一次 for(Socket s: TcpServer_2.socketList) { PrintStream ps = new PrintStream(s.getOutputStream()); ps.println(connect); } } }catch(IOException e) { e.printStackTrace(); } } //定义读取客户端数据的方法 private String readFromClient() { try { return br.readLine(); } //如果捕捉到异常,表明该Socket对应的客户端已经关闭 catch(IOException e) { //删除该Socket TcpServer_2.socketList.remove(s); } return null; } }
三. TcpClient_2.java
import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.Socket; import java.io.IOException; public class TcpClient_2 { public static void main(String[] args) throws IOException { Socket s = new Socket("192.168.31.168", 30001); //客户端启动ClientThread线程不断读取来自服务器的数据 new Thread(new ClientThread(s)).start(); //获取该Socket对应的输出流 PrintStream ps = new PrintStream(s.getOutputStream()); String line = null; //不断读取键盘输入 BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); while((line=br.readLine()) != null) { //将用户的键盘输入内容写入Socket对应的输出流 ps.println(line); } } }
四. ClientThread.java
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.Socket; public class ClientThread implements Runnable { //该线程负责处理的Socket private Socket s; //该线程所处理的Socket所对应的输入流 BufferedReader br = null; public ClientThread(Socket s)throws IOException { this.s = s; br = new BufferedReader(new InputStreamReader(s.getInputStream())); } public void run() { try { String connect = null; //不断读取Socket输入流中的内容,并将这些内容打印输出 while((connect = br.readLine()) != null) { System.out.println(connect); } }catch(Exception e) { e.printStackTrace(); } } }
五.编译:
因为有多个java文件,所以用javac *.java编译
六. 运行结果
电脑A先运行服务端:
电脑A开另外一个终端运行客户端,电脑B也运行一个客户端:
实际测试,运行多个客户端也是可以的,只要有一个客户端发消息,其它客户端都会收到。服务端也起到一个消息转发的作用。