系统需求
1.实现多个用户即时通信的群聊功能
实现分析
1.当服务端接入一个客户端时,为避免阻塞,并接受其他客户端的接入,为该socket开一个线程管理它。
2.当所接入的客户端中,有客户端发送信息时,服务端接收消息,并将此消息发向其他客户端,从而实现简单的群聊功能。
二、使用步骤
1.服务端
利用循环和accept()的阻塞性,在为每一个客户端开一个线程来实现同时接入多个客户端
要注意,每当接收到一个新的客户端,需要将socket存入一个全局的列表,方便服务端对客户端统一管理。
public class Server5 {
//定义一个全局的列表管理socket
public static ArrayList<Socket> sockets = new ArrayList<>();
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(8888);
while(true){
//等待客户端连接,没有连接时则阻塞
Socket socket = serverSocket.accept();
sockets.add(socket);
//给该socket开一个线程
new Thread(new ServerThread(socket)).start();
}
}
}
线程所需要实现的功能有接收所对应客户端的消息,并将此消息发送给其他客户端,这里要用到之前的全局列表;还要监测客户端的状态,当socket的连接出现异常时,说明客户端断开了连接,此时需要将socket从全局列表中删除,并将此socket关闭。
public class ServerThread implements Runnable{
private Socket socket = null;
public ServerThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
//向其他客户端发送自己进入了聊天室
send(socket.getRemoteSocketAddress()+" Enter the room");
System.out.println(socket.getRemoteSocketAddress()+" Enter the room");
} catch (IOException e) {
e.printStackTrace();
}
while(true){
try {
//调用接受消息的函数
String s = recive();
System.out.println(socket.getRemoteSocketAddress()+": "+s);
//向其他客户端发送接收到的消息
send(socket.getRemoteSocketAddress()+": "+s);
} catch (IOException e) {
try {
//出现异常,说明socket断开,客户端断开连接
send(socket.getRemoteSocketAddress()+" 滚出了房间!");
System.out.println(socket.getRemoteSocketAddress()+"滚出了房间!");
//在列表中移除该socket
Server5.sockets.remove(socket);
socket.close();//关闭socket
} catch (IOException ex) {
ex.printStackTrace();
}
break;
}
}
}
//接受客户端的消息
public String recive() throws IOException {
BufferedReader serverRecive =
new BufferedReader(new InputStreamReader(socket.getInputStream()));
return serverRecive.readLine();
}
//向其他客户端发送消息
public void send(String s) throws IOException {
ArrayList<Socket> list = Server5.sockets;
for (int i = 0; i < list.size(); i++) {
if(list.get(i)!=socket){
BufferedWriter serverSend =
new BufferedWriter(new OutputStreamWriter(list.get(i).getOutputStream()));
serverSend.write(s);
serverSend.newLine();
serverSend.flush();
}
}
}
}
2.客户端
客户端需要实现,向服务端发送消息,和接收来自服务端的消息;检测服务端的状态;
public class client5 {
public static void main(String[] args) throws IOException {
//连接服务器
Socket socket = new Socket("192.168.29.170", 8888);
//启动接受消息和发送消息的线程
new Thread(new Send(socket)).start();
new Thread(new Reciver(socket)).start();
}
}
//发送消息
class Send implements Runnable {
private Socket socket = null;
public Send(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
while (true) {
Scanner sc = new Scanner(System.in);
String s = sc.next();
try {
BufferedWriter clientSend =
new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
clientSend.write(s);
clientSend.newLine();
clientSend.flush();
} catch (IOException e) {
System.out.println("服务器关闭!");
break;
}
}
}
}
//接受消息
class Reciver implements Runnable {
private Socket socket = null;
public Reciver(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
while (true) {
try {
BufferedReader clientReciver =
new BufferedReader(new InputStreamReader(socket.getInputStream()));
String s = clientReciver.readLine();
System.out.println(s);
} catch (IOException e) {
System.out.println("服务器关闭!");
break;
}
}
}
}
代码测试
注意看每个端口是不同的,相当于多个客户端