首先说明的是,本帖中的例子是来自网上的一个例子,经过了优化后的结果
实现以下功能:
1.在服务端提示所有客户端发来的消息以及当前的在线人数
2.服务端自动转发新上线用户的IP端口号消息给所有用户(当前用户除外)
3.服务端自动转发当前客户发给其他客户的消息
4.服务端自动转发离线客户的消息
5.服务端接收客户端的断开连接消息,可以断开当前连接
6.客户端连接指定的服务端端口
7.客户端向服务发出普通消息
8.客户端向服务端发出断开连接消息
目前只能实现群聊功能,还无法实现私聊
比如目前有ABC三个用户连接到服务端S,客户端都给服务端发消息,服务端都把在收到的消息广播给其他客户端
客户端代码:
服务端代码:
启动了服务端之后,然后再启动两个或多个客户端,在每个客户端窗口里直接输入要发送的消息按回车,该信息即可被广播到其他的客户端窗口
服务端图片:
[img]http://dl.iteye.com/upload/attachment/462640/0575befe-1eb1-378f-94f0-29776a37513f.jpg[/img]
客户端图片:
[img]http://dl.iteye.com/upload/attachment/462644/f6d57d10-a37a-37ae-b1b5-86175f652dc4.jpg[/img]
[img]http://dl.iteye.com/upload/attachment/462646/b04c6b58-c24f-34d9-ab1e-4a431e98bc49.jpg[/img]
实现以下功能:
1.在服务端提示所有客户端发来的消息以及当前的在线人数
2.服务端自动转发新上线用户的IP端口号消息给所有用户(当前用户除外)
3.服务端自动转发当前客户发给其他客户的消息
4.服务端自动转发离线客户的消息
5.服务端接收客户端的断开连接消息,可以断开当前连接
6.客户端连接指定的服务端端口
7.客户端向服务发出普通消息
8.客户端向服务端发出断开连接消息
目前只能实现群聊功能,还无法实现私聊
比如目前有ABC三个用户连接到服务端S,客户端都给服务端发消息,服务端都把在收到的消息广播给其他客户端
客户端代码:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.*;
public class ChatClient {
private static final int PORT = 8888;
private static ExecutorService exec = Executors.newCachedThreadPool();
private String userId; //用户ID:使用客户端的IP+端口
public static void main(String[] args) throws Exception {
new ChatClient();
}
public ChatClient() {
Socket socket = null;
String msg;
try {
socket = new Socket("localhost", PORT);
//客户端连接到服务端之后,启动一个线程用于接收命令行输入,并且发送到服务端
exec.execute(new Sender(socket));
userId = socket.getInetAddress() + ":"+socket.getLocalPort();
println("[" + userId + "] 您好,欢迎来到阿飞聊天室!");
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while (null != (msg = br.readLine())){
println(msg);
}
} catch (Exception e) { }
}
/**
* 客户端线程获取控制台输入消息,并且向服务发送消息
*/
static class Sender implements Runnable {
private Socket socket;
public Sender(Socket socket) {
this.socket = socket;
}
public void run() {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
PrintWriter pw = new PrintWriter(socket.getOutputStream(), true);
String msg;
while (true) {
//如果用户在命令行中按回车或输入空信息,则不发送到服务端
msg = br.readLine();
if (msg.length()==0){
print(socket.getLocalPort()+":>");
}else{
pw.println(msg);
continue;
}
//客户端发bye退出
if (msg.trim().equals("bye")) {
pw.close();
br.close();
break;
}
//测试消息
if (msg.equals("broadcast")){
msg = "这是来自"+socket.getInetAddress() + ":"+socket.getLocalPort() + " 的测试消息";
pw.println(msg);
}
}
pw.close();
br.close();
socket.close();
exec.shutdownNow();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void print(Object o){
System.out.print(o);
}
public static void println(Object o){
System.out.println(o);
}
}
服务端代码:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.Collections;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ChatServer {
// 端口号
private static final int PORT = 8888;
//创建一个线程安全的的Socket列表,保存Socket对象
private static List<Socket> socketList = Collections.synchronizedList(new ArrayList<Socket>());
//线程池服务对象
private ExecutorService exec;
private ServerSocket server;
public static void main(String[] args) {
new ChatServer();
}
public ChatServer() {
try {
server = new ServerSocket(PORT);
//启动一个线程池
exec = Executors.newCachedThreadPool();
println("阿飞聊天室服务器已启动,监听 "+server.getInetAddress()+":"+server.getLocalPort() +" 端口");
Socket client = null;
while (true) {
//接收客户连接,该套接字将被添加到Socket列表列表中,并且创建一个新的服务线程
client = server.accept();
socketList.add(client);
exec.execute(new ChatTask(client));
}
} catch (IOException e) {
e.printStackTrace();
}
}
//为客户端服务的线程类,负责收发该socket对象的输入和输出信息
class ChatTask implements Runnable {
private Socket socket;
private BufferedReader bufferReader;
private PrintWriter writer;
private String msg;
private int isClosed=0;
private String userId; //用户ID:使用客户端的IP+端口
public ChatTask(Socket socket) throws IOException {
this.socket = socket;
bufferReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
userId = this.socket.getInetAddress() +":"+this.socket.getPort();
msg = "[" + userId + "]进入聊天室!当前聊天室有"
+ socketList.size() + "人";
sendMessage(socket.getPort());//给所有人发消息
}
public void run() {
try {
while ( null != (msg = bufferReader.readLine())){
//服务端收到bye,关闭与该用户的连接
if (msg.trim().equals("bye")) {
socketList.remove(socket);
msg = "[" + userId + "]离开聊天室!当前聊天室有" + socketList.size() + "人";
sendMessage(socket.getPort()); //给别人发
break;
} else {
msg = "[" + userId+ "]说: " + msg;
sendMessage(socket.getPort()); //给别人发
}
try{
Thread.sleep(10);
}catch(Exception e){
e.printStackTrace();
}
}
//关闭服务,关闭的同时也就关闭了InputStream和outputStream,因此不必在上面关闭pw 和 br
socket.close();
bufferReader=null;
writer=null;
} catch (IOException e) {
//e.printStackTrace();
}
}
/**
* 群发消息给聊天室的其他人
*/
private void sendMessage(int selfPort) throws IOException { //Socket selfSocket,boolean toSelf
println(msg);
for (Socket client : socketList) {
if (client.getPort() != selfPort){
writer = new PrintWriter(client.getOutputStream(), true);
writer.println(msg);
}
}
}
}
public static void println(Object o){
System.out.println(o);
}
}
启动了服务端之后,然后再启动两个或多个客户端,在每个客户端窗口里直接输入要发送的消息按回车,该信息即可被广播到其他的客户端窗口
服务端图片:
[img]http://dl.iteye.com/upload/attachment/462640/0575befe-1eb1-378f-94f0-29776a37513f.jpg[/img]
客户端图片:
[img]http://dl.iteye.com/upload/attachment/462644/f6d57d10-a37a-37ae-b1b5-86175f652dc4.jpg[/img]
[img]http://dl.iteye.com/upload/attachment/462646/b04c6b58-c24f-34d9-ab1e-4a431e98bc49.jpg[/img]