JAVA基于TCP的Socket多客户端连接同一服务器使用多线程完成(实现多人聊天功能)

一.题目要求如下:

1.编写客户端程序,连接同一服务器,并实现发送线程和接收线程,发送的信息中应包括“消息+发送时间”,显示消息应包括:“Socket+信息+发送时间”。(GUI实现后续完成)

2.编写服务器端程序,使用TCP Socket启动12345端口,判断该端口是否被占用,可以接收多个客户端的连接(连接成功发出欢迎信息“Welcome”+客户端套接字信息),并将Socket保存在Vector中,将收到的信息转发给所有连接的客户端。(GUI实现后续完成)

二.具体代码实现案例
1.服务器端代码如下:(先有服务器再有客户机,故此处先给出服务器端程序)

package day26.tcp.test;
/*
* 编写服务器端程序,使用TCP Socket启动12345端口,判断该端口是否被占用,可以接收多个客户端的连接
* (连接成功发出欢迎信息“Welcome”+客户端套接字信息),并将Socket保存在Vector中,将收到的信息转
* 发给所有连接的客户端
* */
import java.net.*;
import java.io.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class ServerTest {
    public static void main(String[] args) throws IOException{
        //统计连接客户机并标记,初始为0
        int count = 0;

        //这里用List代替Vector,用来保存客户机的Socket信息
        List li = Collections.synchronizedList(new ArrayList());
        
        //创建服务器Socket对象
        while(true){
            System.out.println("服务器等待建立连接...");
           
            try (ServerSocket ss = new ServerSocket(12345)) {           //这种方式会自动释放资源
                //监听客户端Socket对象
                Socket s = ss.accept();

                //每次有客户机建立连接就标记加一,并且把其Socket信息添加到集合
                count++;
                li.add(s);

                //启动服务器线程
                new Thread(new UserThread(s,count,li)).start();
                System.out.println("连接成功!");


            }catch (IOException e){
                e.printStackTrace();
            }

        }

    }
}


2.服务器端的多线程实现类UserThread

package day26.tcp.test;
/**
 * 服务器多线程实现,用来提高效率
 */
 
import java.io.*;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

public class UserThread implements Runnable {
    private int count;
    private Socket s;
    private  List li;

    public UserThread(Socket s, int count, List li) {
        this.s = s;
        this.count = count;
        this.li = li;
    }

    @Override
    public void run() {
        try {
            //连接成功,给出反馈,连接时间和welcome+ip+port
            SimpleDateFormat date = new SimpleDateFormat(
                    "yyyy-MM-dd HH:mm:ss");
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
                    s.getOutputStream()));

            String str = "ip:" + s.getInetAddress().getHostAddress()  + "-->主机"
                    + count +   "号  port:" + s.getPort() ;
            bw.write("Welcome    " + str+ "   " + date.format(new Date()));
            bw.newLine();
            bw.flush();

            //收到信息发送给所有连接客户端,除了自己
            BufferedReader br = new BufferedReader(new InputStreamReader(
                    s.getInputStream()));

            String line = null;
            while ((line = br.readLine()) != null) {
                if(!li.isEmpty()) {
                    for (Socket _s : li) {
                        if(!_s.equals(s)){
                            BufferedWriter _bw = new BufferedWriter(new OutputStreamWriter(
                                    _s.getOutputStream()));
                            _bw.write(str + " 的用户说:" + " " + line);
                            _bw.newLine();
                            _bw.flush();
                        }

                    }
                }
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}





3.客户端的代码如下:(使用发送接收线程实现)

package day26.tcp.test;
/**
*  编写客户端程序,连接上题服务器,并实现发送线程和接收线程,发送的信息中应包括
*  消息+发送时间,显示消息应包括:Socket+信息+发送时间
*  TODO:GUI?(后续完成)
* /

import java.net.*;
import java.io.*;

public class ClientTest {
    public static void main(String[] args) throws IOException {
    
        //创建Socket对象,指定ip和端口
        Socket s = new Socket("192.168.1.174",12345);


        //包装输入输出流,用作参数传递
        BufferedReader br = new BufferedReader(new InputStreamReader(
                s.getInputStream()));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
                s.getOutputStream()));
        SeThread st = new SeThread(bw);    //发送线程类
        ReThread rt = new ReThread(br);    //接收线程类


        //启动发送接收线程
        new Thread(new SeThread(bw)).start();
        new Thread(new ReThread(br)).start();
        
    }

}

4.客户端的发送线程类SeThread

package day26.tcp.test;
/**
 * 客户端发送线程
 */

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.Date;

public class SeThread implements Runnable {     //实现Runnable接口

    //成员变量定义私有
    private BufferedWriter bw;       
    
	//带参构造,传入输出流对象
    public SeThread(BufferedWriter bw) {
        this.bw = bw;
    }


	//重写run()方法
    @Override
    public void run() {
        try {
        	//包装键盘输入
            BufferedReader buf = new BufferedReader(new InputStreamReader(System.in));
			
			
			//客户端发送信息
            String line = null;      //初始化line
            while ((line = buf.readLine()) != null) {
                if ("886".equals(line)) {    //如果客户机输入886
                	buf.close();             //关闭键盘输入流
                    bw.close();              //关闭输出流
                    break;
                }

				//将客户输入的信息传到输出流:“信息+当前时间”
				//客户机发送信息时附带时间
                SimpleDateFormat date = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss");   
                bw.write("“"+line + "”" + "         [" + date.format(new Date()) + "]");
                bw.newLine();
                bw.flush();

            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

5.客户机接收线程类ReThread

package day26.tcp.test;
/**
 * 客户端接收线程
 */

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

public class ReThread implements Runnable {    //实现Runnable接口
	//成员变量定义私有
    private BufferedReader br;

    //带参构造,传入输入流对象
    public ReThread(BufferedReader br) {
        this.br = br;
    }


	//重写run()方法
    @Override
    public void run() {
        try {
            String line = null;    //初始化_line
            while ((line = br.readLine()) != null) {
                System.out.println(line);    //打印此客户机收到的信息

            }

        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

6.先启动服务器程序,再启动三个客户端,模拟多人聊天
JAVA基于TCP的Socket多客户端连接同一服务器使用多线程完成(实现多人聊天功能)_第1张图片
7.主机1号发送消息:“大家好,我是主机1号”,
主机2号发送消息:“你们好,我是主机2号”
主机3号发送消息:“我是主机3号,你们在聊什么?”
注意:本程序设计,不接收自己所发的消息
JAVA基于TCP的Socket多客户端连接同一服务器使用多线程完成(实现多人聊天功能)_第2张图片
JAVA基于TCP的Socket多客户端连接同一服务器使用多线程完成(实现多人聊天功能)_第3张图片
JAVA基于TCP的Socket多客户端连接同一服务器使用多线程完成(实现多人聊天功能)_第4张图片

你可能感兴趣的:(JAVA网络编程)