其实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端代码:
package com.ryan.chatRoom;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Server1 {
private List<Socket> socketList;
private Socket socket;
private ServerSocket server;
private ExecutorService service;
private DataOutputStream dos;
public Server1() throws IOException {
server = new ServerSocket(10000);
socketList = new ArrayList<>();
service = Executors.newCachedThreadPool();
System.out.println("waiting for client...");
while (true){
socket = server.accept();
socketList.add(socket);
System.out.println("Client comes...total:" + socketList.size());
dos = new DataOutputStream(socket.getOutputStream());
dos.writeUTF("message from server: connect successfully");
//dos.close();
service.execute(new ServerThread(socket));
}
}
private class ServerThread implements Runnable{
Socket socket;
DataOutputStream dos;
DataInputStream dis;
String textFromClient;
public ServerThread(Socket socket) throws IOException {
this.socket = socket;
dis = new DataInputStream(socket.getInputStream());
}
@Override
public void run() {
try {
while ((textFromClient=dis.readUTF())!=null){
if(textFromClient.equals("exit")){
//socket.close();
socketList.remove(socket);
//dis.close();
//dos.close();
System.out.println("client leaves...current client:" + socketList.size());
}else {
for (Socket socket : socketList) {
dos = new DataOutputStream(socket.getOutputStream());
dos.writeUTF(textFromClient);
}
}
}
} catch (IOException e) {
}
}
}
public static void main(String[] args) throws IOException {
new Server1();
}
}
Client端代码:
package com.ryan.chatRoom;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Client1 {
private Socket socket;
private Scanner scanner;
private DataInputStream dis;
private DataOutputStream dos;
private String textFromServer;
private ExecutorService services;
public Client1() {
try {
socket = new Socket("127.0.0.1", 10000);
dis = new DataInputStream(socket.getInputStream());
System.out.println(dis.readUTF());
services = Executors.newCachedThreadPool();
services.execute(new ClientThread(socket));
while ((textFromServer = dis.readUTF()) != null) {
System.out.println("message from Server:" + textFromServer);
}
} catch (IOException e) {
System.out.println("see you");
System.exit(0);
}
}
private class ClientThread implements Runnable {
Scanner scanner;
DataOutputStream dos;
Socket socket;
String sendToServer;
public ClientThread(Socket socket) throws IOException {
this.socket = socket;
dos = new DataOutputStream(socket.getOutputStream());
scanner = new Scanner(System.in);
}
@Override
public void run() {
while (true) {
try {
sendToServer = scanner.nextLine();
dos.writeUTF(sendToServer);
if(sendToServer.equals("exit")){
socket.close();
dos.close();
dis.close();
services.shutdown();
}
} catch (IOException e) {
System.out.println("see you!");
System.exit(0);
}
}
}
}
public static void main(String[] args) throws IOException {
new Client1();
}
}
注意事项:
- 先启动Server端,再启动Client端。
- Server端只能启动一个,Client端可以启动多个。
-----------------------------------------------------
请尊重作者劳动成果,
转载请注明出处
http://blog.csdn.net/wait_notify/article/details/69372571