Socket一对一聊天实例

源码下载:http://download.csdn.net/detail/u011983531/9266041

一、服务端

服务端目录结构如下:
这里写图片描述

这里定义了三个模型:

  • User:对用户的封装,这里只添加了一个name属性
  • Cient:对客户端的封装,客户端包括一个User对象和一个Socket对象
  • Message:对聊天双方传送的消息的封装,包括发送人、接收人、消息内容、消息类型(有上线、下线、聊天三种类型的消息)

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<Client> onlines;//在线客户端
    private static Set<User> users;//在线用户

    static{
        try {
            //创建Socket服务器
            serverSocket = new ServerSocket(PORT);
            onlines = new HashSet<Client>();
            users = new HashSet<User>();
        } 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):
这里写图片描述

2、聊天模块
聊天界面:
这里写图片描述

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就可以了。

  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值