package socket;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Arrays;
import java.util.Scanner;
/**
* 聊天室服务端
* @author ckx
*
*/
public class Server {
/*
* 运行在服务端的ServerSocket
* 有两个作用
* 1.向系统申请服务端口,客户端就是
* 通过这个端口与服务端程序建立联系的
* 2.监听该端口,当客户端通过该端口与服务端
* 建立连接时会自动创建一个socket。通过
* socket与客户端进行数据交互
*/
private ServerSocket server;
/*
* 该数组用于保存所有从clentHandler内部
* 对应客户端输出流,以便广播
* 对此我们在Serber中定义该数组,所有的
* 内部类clentHandler都可以看到它
* 这样将这些clentHandler需要共享的 数据存入
* 这个数组即可
*/
private PrintWriter [] allOut = {};
public Server(){
try{
/*
* 实例化ServerSock的同时向系统申请服务端口
* 该端口不能与系统运行的其他应用程序相同,否则会
* 抛出地址被占用的异常
*/
System.out.println("正在启动服务端...");
server = new ServerSocket(8088);
System.out.println("服务端启动完毕...");
}catch(Exception e){
e.printStackTrace();
}
}
public void start(){
try{
Scanner scanner = new Scanner(System.in);
/*
*ServerSocket有一个中烟的方法:
*Scoket accept()
*该方法是一个阻塞方法,调用后程序就在这里
*卡住了,这时开始监听服务端口等待客户端的连接,那么当客户端通过端口
*尝试连接是,accept会返回一个Socket
*通过Socket就可以与刚连接的客户端进行交互了
*/
System.out.println("等待客户端连接...");
Socket socket = server.accept();
System.out.println("一个客户端连接...");
//启动一个线程来处理客户端
ClientHandler handler
= new ClientHandler(socket);
Thread t1 = new Thread(handler);
t1.start();
/*
* 通过Socket 获取输入流,读取客户端法师过来的数据
*
*/
}catch(Exception e){
e.printStackTrace();
}
}
public static void main(String[] args) {
Server server = new Server();
server.start();
}
/*
* 该线程任务是与指定的Scoket对应的客户端今昔
* 数据交互
*/
private class ClientHandler implements Runnable{
private Socket socket;
public ClientHandler(Socket socket){
this.socket = socket;
}
public void run(){
System.out.println("启动一个线程处理客户端信息");
PrintWriter pw = null;
try{
InputStream in
= socket.getInputStream();
InputStreamReader isr
= new InputStreamReader(in,"UTF-8");
BufferedReader br
= new BufferedReader(isr);
/**
* 通过Socket获取输出流,给该客户端发送消息
*/
OutputStream out = socket.getOutputStream();
OutputStreamWriter osw =new OutputStreamWriter(out,"UTF-8");
BufferedWriter bw = new BufferedWriter(osw);
pw = new PrintWriter(bw,true);
/*
* 将当前clentHandler对应客户端的
* 输出流存入allout数组中,以便其他
* clentHandler在接收消息后可以将消息
* 发送给当前客户端
*/
//1先对allOut数组扩容
allOut = Arrays.copyOf(allOut, allOut.length-1);
allOut[allOut.length] = pw;
//2将当前的pw存入到数组最后一个位置上
String message = null;
while((message = br.readLine())!=null){
System.out.println("客户端说:"+message);
//遍历allOut,将消息发送给所有客户端
for(int i =0;i<allOut.length;i++){
allOut[i].println("客户端说:"+message);
}
}
}catch (Exception e) {
// TODO: handle exception
}finally {
//处理客户端断开连接后的操作
//将当前客户端输出流PW从alout数组中删除
for(int i =0;i<allOut.length;i++){
if(allOut[i]==pw){
//将最后一个元素放在这里
allOut[i] = allOut[allOut.length-1];
//缩容
allOut = Arrays.copyOf(allOut, allOut.length-1);
}
}
//将socket关闭
try {
socket.close();
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
}
}
}
JAVA聊天室十二
这篇博客介绍了如何使用Java的Socket类构建一个简单的聊天室服务端。服务端通过ServerSocket创建并监听8088端口,等待客户端连接。每当有新的客户端连接时,就会启动一个新的线程来处理客户端的输入和输出。服务端能够接收到客户端的消息,并广播给所有已连接的客户端。博客详细展示了代码实现,包括输入输出流的处理和异常处理。
摘要由CSDN通过智能技术生成