其实Socket这个问题困扰我好久了,一直没有好好梳理过,今天花了一天的时间,看了很多资料,写了一个基于Socket的无GUI聊天室,算是对Socket的一个总结吧。
关于Socket和SocketServer,这里就不多解释了。直接看图。
说明几点:
- accept是阻塞式的,它会一直等待Client的连接,直到有Client连接时,accept之后的代码才会被执行。
- 输入输出流的选择可以有很多方式,建议选择DataInputStream和DataOutputStream,因为DataInputStream在读取内容时,直接一个readUTF就可以了,可以省去很多不必要的麻烦。
思路:
- 服务端:
- 考虑到接入的客户端不只一个,因此服务端需要一个List来装接入的Socket连接。一个连接代表一个Client。
- 启动两个线程。一个线程用于接收接入的Client,另一个线程用于接收Client发来的消息,并将消息发送给所有Client(本质即迭代List)。
- 客户端:
- 客户端也需要启动两个线程。一个线程用于接收Server发来的消息(实际上是别的Client发给Server,Server转发过来的)。另一个线程用于像Server发送消息。
- 其它:
- 需要注意关闭socket时抛异常的情况(因为一个线程还在不停的等待读取信息)。
- 至于两个线程怎么开,自由度很大,可以自己决定。
Server端代码:


1 package com.ryan.chatRoom; 2 3 import java.io.DataInputStream; 4 import java.io.DataOutputStream; 5 import java.io.IOException; 6 import java.net.ServerSocket; 7 import java.net.Socket; 8 import java.util.ArrayList; 9 import java.util.List; 10 import java.util.concurrent.ExecutorService; 11 import java.util.concurrent.Executors; 12 13 public class Server1 { 14 15 private List<Socket> socketList; 16 private Socket socket; 17 private ServerSocket server; 18 private ExecutorService service; 19 private DataOutputStream dos; 20 21 public Server1() throws IOException { 22 23 server = new ServerSocket(10000); 24 socketList = new ArrayList<>(); 25 service = Executors.newCachedThreadPool(); 26 27 System.out.println("waiting for client..."); 28 while (true){ 29 socket = server.accept(); 30 socketList.add(socket); 31 System.out.println("Client comes...total:" + socketList.size()); 32 dos = new DataOutputStream(socket.getOutputStream()); 33 dos.writeUTF("message from server: connect successfully"); 34 //dos.close(); 35 service.execute(new ServerThread(socket)); 36 37 } 38 } 39 40 private class ServerThread implements Runnable{ 41 Socket socket; 42 DataOutputStream dos; 43 DataInputStream dis; 44 String textFromClient; 45 46 public ServerThread(Socket socket) throws IOException { 47 this.socket = socket; 48 dis = new DataInputStream(socket.getInputStream()); 49 } 50 51 52 @Override 53 public void run() { 54 try { 55 while ((textFromClient=dis.readUTF())!=null){ 56 if(textFromClient.equals("exit")){ 57 //socket.close(); 58 socketList.remove(socket); 59 //dis.close(); 60 //dos.close(); 61 System.out.println("client leaves...current client:" + socketList.size()); 62 }else { 63 for (Socket socket : socketList) { 64 dos = new DataOutputStream(socket.getOutputStream()); 65 dos.writeUTF(textFromClient); 66 } 67 } 68 } 69 } catch (IOException e) { 70 71 } 72 } 73 } 74 75 public static void main(String[] args) throws IOException { 76 new Server1(); 77 } 78 }
Client端代码:


1 package com.ryan.chatRoom; 2 3 import java.io.DataInputStream; 4 import java.io.DataOutputStream; 5 import java.io.IOException; 6 import java.net.Socket; 7 import java.util.Scanner; 8 import java.util.concurrent.Executor; 9 import java.util.concurrent.ExecutorService; 10 import java.util.concurrent.Executors; 11 12 13 public class Client1 { 14 15 private Socket socket; 16 private Scanner scanner; 17 private DataInputStream dis; 18 private DataOutputStream dos; 19 private String textFromServer; 20 private ExecutorService services; 21 22 public Client1() { 23 try { 24 socket = new Socket("127.0.0.1", 10000); 25 dis = new DataInputStream(socket.getInputStream()); 26 System.out.println(dis.readUTF()); 27 services = Executors.newCachedThreadPool(); 28 services.execute(new ClientThread(socket)); 29 30 while ((textFromServer = dis.readUTF()) != null) { 31 System.out.println("message from Server:" + textFromServer); 32 } 33 } catch (IOException e) { 34 System.out.println("see you"); 35 System.exit(0); 36 } 37 38 } 39 40 private class ClientThread implements Runnable { 41 42 Scanner scanner; 43 DataOutputStream dos; 44 Socket socket; 45 String sendToServer; 46 47 public ClientThread(Socket socket) throws IOException { 48 this.socket = socket; 49 dos = new DataOutputStream(socket.getOutputStream()); 50 scanner = new Scanner(System.in); 51 } 52 53 @Override 54 public void run() { 55 while (true) { 56 try { 57 sendToServer = scanner.nextLine(); 58 dos.writeUTF(sendToServer); 59 if(sendToServer.equals("exit")){ 60 socket.close(); 61 dos.close(); 62 dis.close(); 63 services.shutdown(); 64 } 65 } catch (IOException e) { 66 System.out.println("see you!"); 67 System.exit(0); 68 } 69 } 70 } 71 } 72 73 public static void main(String[] args) throws IOException { 74 new Client1(); 75 } 76 }
注意事项:
- 先启动Server端,再启动Client端。
- Server端只能启动一个,Client端可以启动多个。
-----------------------------------------------------
请尊重作者劳动成果,
转载请注明出处:http://www.cnblogs.com/ryanyu/p/6669030.html