一、需求分析
- 用户与用户之间1-1或1-n通讯
二、技术分析
(一)客户端
- 客户端的功能有两个:发消息和接消息
- 发消息:使用Socket技术的流式输出,配合打印流封装发送。
- 接信息:使用读取专用线程,搭配字符缓冲流读取。
(二)服务端
- 服务端的功能:转发消息。
- 实现转发功能:
- 1、创建服务通道ServerSocket
- 2、建立线程池ExecutorService->ThreadPoolExecutor
- 3、等待连接
- 4、向集合添加通道对象
- 5、添加转发任务到线程池任务队列
- 6、转发线程类的重写
- 第 1 部分:接收信息: 字符缓冲流读取接收的信息。
- 第 2 部分:转发信息: 遍历所有通道,获取输出流输出数据。
三、实现代码
客户端
class Client1{
public static void main(String[] args) {
try {
//建立通道
Socket sender = new Socket(InetAddress.getLocalHost().getHostAddress(),7777);
new ClientServiceThread(sender).start();
Scanner in = new Scanner(System.in);
if (sender.isConnected()) System.out.println(sender.getRemoteSocketAddress() + " 已连接!");
//输出流
PrintStream outStream = new PrintStream(sender.getOutputStream(),true);
String message;
while(!(message = in.nextLine()).equals("exit")){
outStream.println(message);
}
} catch (IOException e) {
System.out.println("连接已断开");
}
}
}
class Client2{
public static void main(String[] args) {
try {
//建立通道
Socket sender = new Socket(InetAddress.getLocalHost().getHostAddress(),7777);
new ClientServiceThread(sender).start();
Scanner in = new Scanner(System.in);
if (sender.isConnected()) System.out.println(sender.getRemoteSocketAddress() + " 已连接!");
//输出流
PrintStream outStream = new PrintStream(sender.getOutputStream(),true);
String message;
while(!(message = in.nextLine()).equals("exit")){
outStream.println(message);
}
} catch (IOException e) {
System.out.println("连接已断开");
}
}
}
class ClientServiceThread extends Thread{
private Socket socket;
public ClientServiceThread(){}
public ClientServiceThread(Socket socket){
this.socket = socket;
}
@Override
public void run() {
try {
InputStream in = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String message;
while((message = br.readLine()) != null){
System.out.println(socket.getRemoteSocketAddress() + " " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(System.currentTimeMillis()));
System.out.println(message);
}
} catch (IOException e) {
System.out.println("服务器将您踢出群聊······");
}
}
}
服务端
class Server{
public static List<Socket> sockets = new ArrayList<>();
public static void main(String[] args) {
try {
ServerSocket socket = new ServerSocket(7777);
ExecutorService service = new ThreadPoolExecutor(3,5,5, TimeUnit.SECONDS,new LinkedBlockingDeque<>(4),new ThreadPoolExecutor.AbortPolicy());
while(true){
Socket accept = socket.accept();
System.out.println(accept.getRemoteSocketAddress() + "已上线!时间:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(System.currentTimeMillis()));
sockets.add(accept);
service.execute(new ServerThread(accept));
}
} catch (IOException e) {
System.out.println();
}
}
}
class ServerThread implements Runnable{
private Socket socket;
public ServerThread() {
}
public ServerThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
System.out.println(socket.getRemoteSocketAddress() + " 已上线,上线时间:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(System.currentTimeMillis()));
String message;
while((message = reader.readLine())!=null){
//获取信息
System.out.println(socket.getRemoteSocketAddress() + " " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
System.out.println(message);
//使用转发技术,转发其它客户端
sendMessageAll(message);
}
} catch (IOException e) {
System.out.println(socket.getRemoteSocketAddress() + ",下线了,时间:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
Server.sockets.remove(socket);
}
}
private void sendMessageAll(String message) {
for (Socket socket :Server.sockets) {
try {
PrintStream ps = new PrintStream(socket.getOutputStream(),true);
ps.println(message);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
效果图