其实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 ListsocketList;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 @Override53 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 @Override54 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