源码下载:http://download.csdn.net/detail/u011983531/9266041
这里定义了三个模型:
ChatServer.java
package com.ghs.chat.server;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashSet;
import java.util.Set;
import com.ghs.chat.bean.Client;
import com.ghs.chat.bean.Message;
import com.ghs.chat.bean.User;
public class ChatServer {
private static final int PORT = 5000;
private static ServerSocket serverSocket;
private static Set onlines;//在线客户端
private static Set users;//在线用户
static{
try {
//创建Socket服务器
serverSocket = new ServerSocket(PORT);
onlines = new HashSet();
users = new HashSet();
} catch (IOException e) {
e.printStackTrace();
}
}
public void start(){
//服务器始终监听5000端口,当有客户顿请求建立连接时,就开启一个线程,处理该请求
try {
while(true){
Socket socket = serverSocket.accept();
new HandlerClientRequestThread(socket).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
class HandlerClientRequestThread extends Thread{
private Socket socket = null;//请求建立连接的客户端
private Message message = null;//客户端发来的消息
public HandlerClientRequestThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
while(true){
ObjectInputStream ois= new ObjectInputStream(socket.getInputStream());
message = (Message) ois.readObject();
int type = message.getType();
User user = null;
Message msg = null;
switch (type) {
case Message.ON_LINE://当有客户端上线时,向所有客户端发送消息
user = message.getFromUser();
onlines.add(new Client(user,socket));
users.add(user);
// System.out.println(user.hashCode()+"..."+users.size());
msg = new Message();
msg.setContent(users);
msg.setType(Message.ON_LINE);
sendMessageToAll(msg);
break;
case Message.OUT_LINE:
user = message.getFromUser();
onlines.remove((new Client(user,socket)));
users.remove(user);
msg = new Message();
msg.setContent(users);
msg.setType(Message.OUT_LINE);
sendMessageToAll(msg);
break;
case Message.CHATTING://客户端正在聊天
sendMessage(message);
break;
default:
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 将发送端的消息转发给接收端
* @param message
*/
private void sendMessage(Message message){
//根据发送端指定的接收端的用户,获取接收端的Socket
User toUser = message.getToUser();
System.out.println(toUser.getName()+"..."+message.getContent());
Socket toSocket=null;
for (Client client:onlines) {
if(toUser.getName().equals(client.getUser().getName())){
toSocket = client.getSocket();
}
}
System.out.println(toSocket==null);
//如果接收端在线,就将消息转发给接收端
if(toSocket!=null){
try {
ObjectOutputStream oos = new ObjectOutputStream(toSocket.getOutputStream());
oos.writeObject(message);
oos.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//给所有在线客户端发送消息
private void sendMessageToAll(Message message){
for(Client client:onlines){
try {
ObjectOutputStream oos = new ObjectOutputStream(client.getSocket().getOutputStream());
oos.writeObject(message);
oos.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void sendMessage(Message message,Socket socket){
try {
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(message);
oos.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
new ChatServer().start();
}
}
服务端通过Socket socket = serverSocket.accept(); 不停的监听5000端口,每当有客户端请求建立连接时,就创建一个处理客户端请求的线程,每一个线程代表一个与客户端建立的连接。然后在线程内部通过ObjectInputStream ois= new ObjectInputStream(socket.getInputStream()); 不停的接收客户端发送的消息,收到消息后,再把消息转发给另一个客户端。
客户端主要分为两大块,一个是登录模块,另一个是聊天模块。
1、登录模块
首先在mysql数据库中创建一个数据库chat,然后创建一张表tbl_user,如下:
DBUtils.java就是用来与数据库创建连接的,UserService.java就是用来处理登录逻辑的。
登录界面(LoginFrame.java):
ChatClient.java
package com.ghs.chat.client;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import com.ghs.chat.bean.Client;
import com.ghs.chat.bean.Message;
import com.ghs.chat.bean.User;
import com.ghs.chat.listener.ReceivedMsgListener;
public class ChatClient {
private static final String HOST = "127.0.0.1";
private static final int PORT = 5000;
private static Socket socket;
private ReceivedMsgListener listener = null;
static{
try {
socket = new Socket(HOST,PORT);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 接收消息
*/
public void receiveMsg(){
new Thread(new Runnable() {
@Override
public void run() {
//客户端不停的接收消息
while(true){
try {
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
Message message = (Message) ois.readObject();
listener.onReceived(message);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}).start();
}
/**
* 发送消息
* @param content
* @param from 发送人
* @param to 接收人
*/
public void sendMsg(String content,String from,String to){
System.out.println(content+"..."+from+"..."+to);
Message message = new Message();
message.setContent(content);
message.setFromUser(new User(from));
message.setToUser(new User(to));
message.setType(Message.CHATTING);
try {
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(message);
oos.flush();
System.out.println("finish");
} catch (IOException e) {
e.printStackTrace();
}
}
public void sendMsg(Message message){
ObjectOutputStream oos;
try {
oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(message);
oos.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 客户端上线后,向服务端发送消息
* @param from
*/
public void online(String from){
Message message = new Message();
message.setFromUser(new User(from));
message.setType(Message.ON_LINE);
try {
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(message);
oos.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 客户端下线后,向服务端发送消息
* @param from
*/
public void outline(String from){
Message message = new Message();
message.setFromUser(new User(from));
message.setType(Message.OUT_LINE);
try {
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(message);
oos.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
public void setReceivedMsgListener(ReceivedMsgListener listener){
this.listener = listener;
}
}
当用户登录成功后,会实例化一个Client对象,即与服务端建立连接,然后调用online()方法通知服务端上线了,当用户退出后,会调用outLine()方法通知服务端下线了。另外,客户端定义了一个线程,通过ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream()); 不停的接收服务端发送的消息。当收到消息后,就会调用ReceivedMsgListener中的onReceived方法,因为ChatFrame实现了这个接口,所以具体怎么显示交给ChatFrame就可以了。