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();
    }
    
}
时间: 2024-08-01 17:38:55

Java网络编程基础(四)---基于TCP的简单聊天系统的相关文章

Java网络编程基础(六)— 基于TCP的NIO简单聊天系统

在Java网络编程基础(四)中提到了基于Socket的TCP/IP简单聊天系统实现了一个多客户端之间护法消息的简单聊天系统.其服务端采用了多线程来处理多个客户端的消息发送,并转发给目的用户.但是由于它是基于Socket的,因此是阻塞的. 本节我们将通过SocketChannel和ServerSocketChannel来实现同样的功能. 1.客户端输入消息的格式 username:msg    username表示要发送的的用户名,msg为发送内容,以冒号分割 2.实现思路 实现思路与Java网络

Java网络编程和NIO详解开篇:Java网络编程基础

Java网络编程和NIO详解开篇:Java网络编程基础 计算机网络编程基础 转自:https://mp.weixin.qq.com/s/XXMz5uAFSsPdg38bth2jAA 我们是幸运的,因为我们拥有网络.网络是一个神奇的东西,它改变了你和我的生活方式,改变了整个世界. 然而,网络的无标度和小世界特性使得它又是复杂的,无所不在,无所不能,以致于我们无法区分甚至无法描述. 对于一个码农而言,了解网络的基础知识可能还是从了解定义开始,认识OSI的七层协议模型,深入Socket内部,进而熟练地

【Java】Java网络编程菜鸟进阶:TCP和套接字入门

Java网络编程菜鸟进阶:TCP和套接字入门 JDK 提供了对 TCP(Transmission Control Protocol,传输控制协议)和 UDP(User Datagram Protocol,用户数据报协议)这两个数据传输协议的支持.本文开始探讨 TCP. TCP 基础知识 在“服务器-客户端”这种架构中,服务器和客户端各自维护一个端点,两个端点需要通过网络进行数据交换.TCP 为这种需求提供了一种可靠的流式连接,流式的意思是传出和收到的数据都是连续的字节,没有对数据量进行大小限制.

java 网络编程(三)---TCP的基础级示例

下面是TCP java网络编程的基础示例: tcp传输:客户端建立过程的思路:1.创建TCP客户端的Socket服务,使用的是socket对象,建议在创建的过程中,就明确了目的地和要连接的主机2.如果连接建立成功,说明数据传输通道已经建立,该通道就是Socket的I/O流,是底层建立好的,既然是流,就说明有输入流,就有输出流,要换取就找socket获取相关的流即可,   getInputStream()和getOutputStream()的字节流.3.使用输出流,将数据输出:使用输入流,把数据输

Java网络编程基础【转】

网络编程 网络编程对于很多的初学者来说,都是很向往的一种编程技能,但是很多的初学者却因为很长一段时间无法进入网络编程的大门而放弃了对于该部分技术的学习. 在 学习网络编程以前,很多初学者可能觉得网络编程是比较复杂的系统工程,需要了解很多和网络相关的基础知识,其实这些都不是很必需的.首先来问一个问题:你 会打手机吗?很多人可能说肯定会啊,不就是按按电话号码,拨打电话嘛,很简单的事情啊!其实初学者如果入门网络编程的话也可以做到这么简单! 网络编程就是在两个或两个以上的设备(例如计算机)之间传输数据.

【转】JAVA网络编程基础

转来自己学习用 转自http://www.cnblogs.com/springcsc/archive/2009/12/03/1616413.html 网络编程 网络编程对于很多的初学者来说,都是很向往的一种编程技能,但是很多的初学者却因为很长一段时间无法进入网络编程的大门而放弃了对于该部分技术的学习. 在 学习网络编程以前,很多初学者可能觉得网络编程是比较复杂的系统工程,需要了解很多和网络相关的基础知识,其实这些都不是很必需的.首先来问一个问题:你 会打手机吗?很多人可能说肯定会啊,不就是按按电

Java网络编程和NIO:Java网络编程基础

转自: https://www.cnblogs.com/midiyu/p/7875574.html 关于网络 网络协议 如同人与人之间相互交流是需要遵循一定的规矩一样,计算机之间能够进行相互通信是因为它们都共同遵守一定的规则,即网络协议. 网络体系结构 计算机网络是个复杂的系统,按照人们解决复杂问题的方法,把计算机网络实现的功能分到不同的层次上,层与层之间用接口连接.通信的双方具有相同的层次,层次实现的功能由协议数据单元(PDU)来描述.不同系统中的同一层构成对等层,对等层之间通过对等层协议进行

Java网络编程基础

一.Java网络编程 网络编程在如今这样的网络时代是十分重要的,Java语言提供了丰富的类库来支持网络编程.这里将重点介绍Java.net中的类,充分了解认识Java网络编程的原理并深入学习各模块.在学习Java网络编程之前首先需要具备一定的网络知识:网络的层次结构,常见的网络协议(TCP/IP),IP地址端口号等等.需要学习了解这些内容,可以参考前面的文章. 二.主机地址和IP地址 在进行网络访问时,每个主机都有IP地址,也有主机名(域名),为了便于处理与之相关的问题,Java.net包中提供

Java网络编程基础(一)

Java SDK提供一些相对简单的API来完成网络功能,这些API存在于java.net包里面,Java所提供的网络功能可大致分为三类. 基于HTTP协议的网络编程:这是三大类功能中最高级的一种.通过URL的网络资源表达方式,很容易确实网络上数据的位置.利用URL和URLConnection,Java程序可以直接读入网络上所放的数据,或者自己的数据传送到网络的另一端 基于TCP/IP协议的Socket编程:可以想象成两个不同的程序通过网络的通道,而这时传统网络程序中的最常用的方法.一般在TCP/

Java网络编程基础(二)-- 基于TCP/IP的Socket编程

本节讲点: 客户端套接字:Socket:Socket的创建和使用方法,以及Socket选项和异常. 服务端套接字:ServerSocket:SeverSocket的创建和使用方法,以及ServerSocket选项 简单的Client/Server对话程序 支持多客户端的Client/Server服务响应程序 在学习JDK的网络编程之前先要了解一下网络基础知识和网络协议. TCP(传输控制协议)一种基于连接的通信协议.可靠传输 UDP(用户数据包协议)不稳定连接的通信协议 TCP和UDP的端口如下