Java网络编程基础---基于TCP的简单聊天系统

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java网络编程基础---基于TCP的简单聊天系统相关的知识,希望对你有一定的参考价值。

实现思路:

    要实现消息的发送,客户端每次在连接服务器端时都需要告诉服务器自己的用户名,以便能够接收到发送给自己的消息。服务器端在接收到消息时,能够查到对应用户名的客户端,将消息发送给该客户端。

    服务端需要实现多个客户端的同时请求,因此需要使用多线程来处理客户端的请求。同时,它还需要保存一份用户名列表,以便在转发消息时能够查找到对应的用户。

    对于客户端来说,客户端需要能够随时收取服务器端转发来的消息,并能够随时通过键盘输入发送消息,因此它的读取消息和发送消息功能是并行的,需要独立的线程来实现。


实现过程:

    根据以上思路,客户端和服务端都需要独立的线程,因此分别包含了一个主程序和一个子线程类,共需要实现4个类。

    (1)、客户端主程序ChatClient.java

        该程序根据启动时输入的用户名参数,负责启动客户端的子线程,由子线程建立客户端和服务器的连接。在主线程中,需要循环读取键盘的输入,将输入的信息通过子线程发送给服务器,交由服务器来转发该消息给客户端。

    (2)、客户端子线程ClientThread.java

        该线程封装了客户端和服务器的所有操作。

        a、在构造函数中,根据用户名创建与服务端的连接,然后发送用户名给服务端进行注册

        b、在线程函数中,循环读取服务端发送的消息,并显示的控制台

        c、还应有一个发送消息的函数,外部的主线程在接收到键盘输入后,调用该函数给服务端发送消息

        d、关闭函数:在客户端输入bye命令后,关闭客户端和服务端连接。

    (3)、服务端主程序ChatServer.java

        该类负责启动服务器,并负责监听客户端的请求,在接收到新的用户端后,交给子线程处理。

    (4)、服务端子线程ServerThread.java

        该线程负责处理客户端的输入\输出和消息转发任务,因此需要包含以下功能

            a、在构造函数中,建立与客户端的输入\输出流,并在第一次建立连接时读取客户端发送的用户名,并将该用户添加到用户列表中。

            b、在主线程函数中,读取客户端的输入数据,如果发送的消息时bye,则推出监听关闭该客户端,否则根据命令格式进行解析。冒号(:)前的部分为用户名,根据该用户名在客户端列表中找到对应的客户端处理线程,发送数据给客户端

            c、发送数据函数:在收到用户消息进行转发时调用

参考样例

1、客户端

package org.test.example;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * @author kucs
 * 客户端主程序
 * 负责调用子线程创建客户端
 * 监听键盘输入
 * 根据系统启动参数取得用户名
 * 调用子线程创建该用户的客户端线程并启动
 */
public class ChatClient {

    public static void main(String[] args) {
        
        try {
            ClientThread client = new ClientThread(args[0]);
            client.start();
            
            //输入\输出流
            BufferedReader sin = new BufferedReader(new InputStreamReader(System.in));
            //循环读取键盘输入
            String readLine;
            while((readLine = sin.readLine()) != null){
                if(readLine.equals("bye")){
                    client.close();
                    System.exit(0);
                }
                client.send(readLine);
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}

2、客户端线程

package org.test.example;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;

/**
 * @author kucs
 * 
 * 受主线程委托,来创建与服务端的连接
 * 监听服务端的消息
 * 负责发送消息给服务端
 */
public class ClientThread extends Thread {
    Socket socket;        //socket对象
    BufferedReader is;    //输入流
    PrintWriter os;        //输出流
    
    //启动客户端
    public ClientThread(String userName) {
        //连接服务器
        try {
            socket = new Socket("127.0.0.1",12345);
            
            //输入输出流
            is = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            os = new PrintWriter(socket.getOutputStream());
            
            //发送用户名
            os.println(userName);
            os.flush();
        } catch (UnknownHostException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    
    @Override
    public void run() {
        try {
            // TODO 循环读取服务端转发的消息
            String readLine;
            while((readLine = is.readLine()) != null){
                System.out.println(readLine);
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public void close() {
        try {
            // TODO 关闭客户端
            is.close();
            os.close();
            
            socket.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public void send(String readLine) {
        // TODO 发送消息
        os.print(readLine);
        os.flush();
    }

}

3、服务端

package org.test.example;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Hashtable;

/**
 * @author kucs
 *
 */
public class ChatServer {
    public static void main(String[] args) {
        ServerSocket server = null;
        try {
            // TODO 启动服务端
            server = new ServerSocket(12345);
            System.out.println("服务端启动:"+
                    server.getInetAddress().getHostAddress()+":"+
                    server.getLocalPort());
            
            //客户端列表
            Hashtable<String, ServerThread> clientList = new Hashtable<String, ServerThread>();
            
            //监听客户端
            while(true){
                Socket socket = server.accept();
                //启动服务端处理线程
                new ServerThread(socket,clientList).start();
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally{
            try {
                server.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

}

4、服务端线程

package org.test.example;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Hashtable;

public class ServerThread extends Thread {
    
    Socket socket;                                //Socket对象
    BufferedReader is;                            //输入流
    PrintWriter os;                                //输出流
    Hashtable<String, ServerThread> clientList;    //客户端列表
    String userName;                            //用户名
    public ServerThread(Socket socket, Hashtable<String, ServerThread> clientList) {
        this.socket = socket;
        this.clientList = clientList;
        
        try {
            //输入输出流
            is = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            os = new PrintWriter(socket.getOutputStream());
            
            //读取用户名
            this.userName = is.readLine();
            clientList.put(userName, this);
            
            //显示连接信息
            System.out.println(userName+"连接:"
                    + socket.getInetAddress().getHostAddress()+":"
                    + socket.getLocalPort());
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    @Override
    public void run() {
        // TODO 循环处理客户端输入
        try {
            String line;
            while((line = is.readLine()) != null){
                //用户输入信息
                System.out.println(userName + "发给"+line);
                if(line.equals("bye")){
                    break;
                }else{
                    //转发消息给客户端
                    String[] arr = line.split(":");
                    if(arr.length == 2){
                        if(clientList.containsKey(arr[0])){
                            clientList.get(arr[0]).send(userName+":"+arr[1]);
                        }
                    }
                }
            }
            is.close();
            os.close();
            
            //关闭客户端
            socket.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    private void send(String msg) {
        // TODO 发送消息
        System.out.println("发给" + userName +" "+msg);
        os.println(msg);
        os.flush();
    }
    
}


本文出自 “阿酷博客源” 博客,请务必保留此出处http://aku28907.blog.51cto.com/5668513/1782187

以上是关于Java网络编程基础---基于TCP的简单聊天系统的主要内容,如果未能解决你的问题,请参考以下文章

Java利用TCP编程实现简单聊天室

基于java TCP实现网络通信聊天室《建议收藏附完整源码》

基于java TCP实现网络通信聊天室《建议收藏附完整源码》

基于TCP的聊天系统

基于TCP的聊天系统

基于TCP的聊天系统