TCP通信(小程序)
server端:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
package chat; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayList; import java.util.List; /** * 聊天室服务端 * @author adminitartor * */ public class Server { /* * 运行在服务端的ServerSocket,主要作用: * 1:向操作系统申请服务端口,客户端就是通过 * 这个端口与服务端程序建立连接的 * 2:监听服务端口,一旦客户端连接了,就会创建 * 一个Socket以便与该客户端交互 */ private ServerSocket server; /* * 该集合存放所有客户端的输出流,以便于广播 * 消息给所有客户端 */ private List<PrintWriter> allOut; /** * 构造方法,用来初始化服务端 * @throws Exception */ public Server() throws Exception{ /* * 初始化,并申请服务端口,若该端口被 * 其他应用程序占用,这里会抛出异常 */ server = new ServerSocket(8088); allOut = new ArrayList<PrintWriter>(); } /** * 广播消息 * @param message */ public void sendMessage(String message){ synchronized (allOut) { for(PrintWriter out : allOut){ out.println(message); } } } public void start(){ try { /* * ServerSocket提供方法: * Socket accept() * 该方法是一个阻塞方法,直到一个客户端 * 通过申请的端口连接上,这里才会返回 * 返回的是一个Socket实例,通过该实例 * 即可与刚连接的客户端交互。 */ while(true){ System.out.println("等待客户端连接..."); Socket socket = server.accept(); System.out.println("一个客户端连接了!"); /* * 当一个客户端连接后,启动一个线程来处理 * 该客户端的交互工作。 */ ClientHandler handler = new ClientHandler(socket); Thread t = new Thread(handler); t.start(); } } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) { try { Server server = new Server(); server.start(); } catch (Exception e) { e.printStackTrace(); System.out.println("服务端运行失败!"); } } /** * 该线程的任务是用来与指定的客户端进行 * 交互 * @author adminitartor * */ private class ClientHandler implements Runnable{ //当前线程通过该Socket与客户端交互 private Socket socket; //该客户端的IP地址信息 private String host; //该客户端的昵称 private String nickName; public ClientHandler(Socket socket){ this.socket = socket; /* * 通过Socket获取远端计算机的地址 * 信息 */ InetAddress address = socket.getInetAddress(); //获取ip地址信息 host = address.getHostAddress(); } public void run(){ PrintWriter pw = null; try { /* * Socket提供了方法: * InputStream getInputStream() * 该方法可以获取一个输入流,通过该流 * 读取到的内容就是远端计算机发送过来的数据 */ InputStream in = socket.getInputStream(); InputStreamReader isr = new InputStreamReader(in,"UTF-8"); BufferedReader br = new BufferedReader(isr); /* * 首先单独读取一行字符串,该字符串为 * 当前客户端的昵称 */ nickName = br.readLine(); /* * 通过Socket获取输出流,以便将消息发送 * 给客户端 */ pw = new PrintWriter( new OutputStreamWriter( socket.getOutputStream(), "UTF-8" ),true ); /* * 将当前客户端的输出流存入共享集合 */ synchronized (allOut) { allOut.add(pw); } //广播当前用户上线 sendMessage(nickName+"上线了..."); String message = null; /* * 读取客户端发送过来的消息时,当客户端断开连接 * 时,由于客户端系统不同,这里readLine方法的 * 执行结果也不同: * 当windows的客户端断开后:这里会抛出异常 * 当linux的客户端断开后:这里会返回null */ while((message = br.readLine())!=null){ // System.out.println(host+"说:"+message); // //将消息发送给客户端 // pw.println(host+"说:"+message); //将消息广播给所有客户端 sendMessage(nickName+"说:"+message); } } catch (Exception e) { } finally{ /* * 处理客户端断开连接后的操作 */ //将该客户端的输出流从共享集合删除 synchronized (allOut) { allOut.remove(pw); } sendMessage(nickName+"下线了..."); try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
client端:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
package chat; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.Socket; import java.util.Scanner; /** * 聊天室客户端 * @author adminitartor * */ public class Client { /* * 封装了TCP通讯的Socket * 使用它可以与服务端建立连接,并进行通讯 * */ private Socket socket; /** * 构造方法,用来初始化客户端 */ public Client() throws Exception{ /* * 实例化Socket的过程就是连接服务端的 * 过程。若连接失败,这里会抛出异常 * * 构造方法的两个参数: * 1:服务端计算机的IP地址 * 2:服务端应用程序的端口 */ socket = new Socket( "localhost",8088 ); } /** * 客户端开始工作的方法 */ public void start(){ try { Scanner scanner = new Scanner(System.in); /* * 先要求用户输入一个昵称: */ String nickName = null; while(true){ System.out.println("请输入您的昵称:"); nickName = scanner.nextLine().trim(); if(nickName.length()>0){ break; } System.out.println("请至少输入一个字符"); } /* * Socket提供了方法: * OutputStream getOutputStream() * 该方法会获取一个输出流,通过该输出 * 流写出的数据会发送给远端计算机。 */ OutputStream out = socket.getOutputStream(); OutputStreamWriter osw = new OutputStreamWriter(out,"UTF-8"); PrintWriter pw = new PrintWriter(osw,true); /* * 输出流创建完毕后先单独将昵称 * 发送至服务端 */ pw.println(nickName); /* * 将读取服务端消息的线程启动起来 */ ServerHandler handler = new ServerHandler(); Thread t = new Thread(handler); t.start(); String message = null; while(true){ message = scanner.nextLine(); pw.println(message); } } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) { try { Client client = new Client(); client.start(); } catch (Exception e) { e.printStackTrace(); System.out.println("客户端运行失败!"); } } /** * 该线程负责接收服务端发送过来的消息并 * 输出到客户端的控制台。 * @author adminitartor * */ private class ServerHandler implements Runnable{ public void run(){ try { BufferedReader br = new BufferedReader( new InputStreamReader( socket.getInputStream(),"UTF-8" ) ); String message = null; while((message = br.readLine())!=null){ System.out.println(message); } } catch (Exception e) { } } } }