server端:
package chat;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
/**
* 聊天室服务端
* @author adminitartor
*
*/
public class Server {
/*
* 运行在服务端的ServerSocket,主要作用:
* 1:向操作系统申请服务端口,客户端就是通过
* 这个端口与服务端程序建立连接的
* 2:监听服务端口,一旦客户端连接了,就会创建
* 一个Socket以便与该客户端交互
*/
private ServerSocket server;
/*
* 该集合存放所有客户端的输出流,以便于广播
* 消息给所有客户端
*/
private List<PrintWriter> allOut;
/**
* 构造方法,用来初始化服务端
* @throws Exception
*/
public Server() throws Exception{
/*
* 初始化,并申请服务端口,若该端口被
* 其他应用程序占用,这里会抛出异常
*/
server = new ServerSocket(8088);
allOut = new ArrayList<PrintWriter>();
}
/**
* 广播消息
* @param message
*/
public void sendMessage(String message){
synchronized (allOut) {
for(PrintWriter out : allOut){
out.println(message);
}
}
}
public void start(){
try {
/*
* ServerSocket提供方法:
* Socket accept()
* 该方法是一个阻塞方法,直到一个客户端
* 通过申请的端口连接上,这里才会返回
* 返回的是一个Socket实例,通过该实例
* 即可与刚连接的客户端交互。
*/
while(true){
System.out.println("等待客户端连接...");
Socket socket = server.accept();
System.out.println("一个客户端连接了!");
/*
* 当一个客户端连接后,启动一个线程来处理
* 该客户端的交互工作。
*/
ClientHandler handler
= new ClientHandler(socket);
Thread t = new Thread(handler);
t.start();
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
try {
Server server = new Server();
server.start();
} catch (Exception e) {
e.printStackTrace();
System.out.println("服务端运行失败!");
}
}
/**
* 该线程的任务是用来与指定的客户端进行
* 交互
* @author adminitartor
*
*/
private class ClientHandler
implements Runnable{
//当前线程通过该Socket与客户端交互
private Socket socket;
//该客户端的IP地址信息
private String host;
//该客户端的昵称
private String nickName;
public ClientHandler(Socket socket){
this.socket = socket;
/*
* 通过Socket获取远端计算机的地址
* 信息
*/
InetAddress address
= socket.getInetAddress();
//获取ip地址信息
host = address.getHostAddress();
}
public void run(){
PrintWriter pw = null;
try {
/*
* Socket提供了方法:
* InputStream getInputStream()
* 该方法可以获取一个输入流,通过该流
* 读取到的内容就是远端计算机发送过来的数据
*/
InputStream in
= socket.getInputStream();
InputStreamReader isr
= new InputStreamReader(in,"UTF-8");
BufferedReader br
= new BufferedReader(isr);
/*
* 首先单独读取一行字符串,该字符串为
* 当前客户端的昵称
*/
nickName = br.readLine();
/*
* 通过Socket获取输出流,以便将消息发送
* 给客户端
*/
pw = new PrintWriter(
new OutputStreamWriter(
socket.getOutputStream(),
"UTF-8"
),true
);
/*
* 将当前客户端的输出流存入共享集合
*/
synchronized (allOut) {
allOut.add(pw);
}
//广播当前用户上线
sendMessage(nickName+"上线了...");
String message = null;
/*
* 读取客户端发送过来的消息时,当客户端断开连接
* 时,由于客户端系统不同,这里readLine方法的
* 执行结果也不同:
* 当windows的客户端断开后:这里会抛出异常
* 当linux的客户端断开后:这里会返回null
*/
while((message = br.readLine())!=null){
// System.out.println(host+"说:"+message);
// //将消息发送给客户端
// pw.println(host+"说:"+message);
//将消息广播给所有客户端
sendMessage(nickName+"说:"+message);
}
} catch (Exception e) {
} finally{
/*
* 处理客户端断开连接后的操作
*/
//将该客户端的输出流从共享集合删除
synchronized (allOut) {
allOut.remove(pw);
}
sendMessage(nickName+"下线了...");
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
client端:
package chat;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
/**
* 聊天室客户端
* @author adminitartor
*
*/
public class Client {
/*
* 封装了TCP通讯的Socket
* 使用它可以与服务端建立连接,并进行通讯
*
*/
private Socket socket;
/**
* 构造方法,用来初始化客户端
*/
public Client() throws Exception{
/*
* 实例化Socket的过程就是连接服务端的
* 过程。若连接失败,这里会抛出异常
*
* 构造方法的两个参数:
* 1:服务端计算机的IP地址
* 2:服务端应用程序的端口
*/
socket = new Socket(
"localhost",8088
);
}
/**
* 客户端开始工作的方法
*/
public void start(){
try {
Scanner scanner = new Scanner(System.in);
/*
* 先要求用户输入一个昵称:
*/
String nickName = null;
while(true){
System.out.println("请输入您的昵称:");
nickName = scanner.nextLine().trim();
if(nickName.length()>0){
break;
}
System.out.println("请至少输入一个字符");
}
/*
* Socket提供了方法:
* OutputStream getOutputStream()
* 该方法会获取一个输出流,通过该输出
* 流写出的数据会发送给远端计算机。
*/
OutputStream out
= socket.getOutputStream();
OutputStreamWriter osw
= new OutputStreamWriter(out,"UTF-8");
PrintWriter pw
= new PrintWriter(osw,true);
/*
* 输出流创建完毕后先单独将昵称
* 发送至服务端
*/
pw.println(nickName);
/*
* 将读取服务端消息的线程启动起来
*/
ServerHandler handler
= new ServerHandler();
Thread t = new Thread(handler);
t.start();
String message = null;
while(true){
message = scanner.nextLine();
pw.println(message);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
try {
Client client = new Client();
client.start();
} catch (Exception e) {
e.printStackTrace();
System.out.println("客户端运行失败!");
}
}
/**
* 该线程负责接收服务端发送过来的消息并
* 输出到客户端的控制台。
* @author adminitartor
*
*/
private class ServerHandler
implements Runnable{
public void run(){
try {
BufferedReader br = new BufferedReader(
new InputStreamReader(
socket.getInputStream(),"UTF-8"
)
);
String message = null;
while((message = br.readLine())!=null){
System.out.println(message);
}
} catch (Exception e) {
}
}
}
}