66 网络编程(五)——TCP多线程实现多人聊天室

思路

  • 客户端读写各一个类,可以使内部类,实现Runnable。读写类都与服务器端建立连接,一个收,一个发。
  • 客户端实现接收和转发。多线程实现每个客户端的连接(使与各客户端的连接独立)。
  • 服务器端中创建一个公共缓冲池,用于存放消息。通过服务器中的转发方法转发给个客户端。

客户端 代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
package _20191218;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
 
/**
 *  多人聊天室,客户端,实时发送接收数据,要实现多线程
 */
 
public class TCPMultipleChatClient {
    public static void main(String[] args) {
        System.out.println("-------局域网聊天室-----------");
        Scanner scan1 = new Scanner(System.in);
        System.out.print("请输入您的昵称:");
        String username = scan1.nextLine();
        String address = "176.195.108.53";//服务器地址
        int port = 6788;//服务器程序端口
        Socket client = null;
        try {
            client = new Socket(address,port);
            System.out.println("成功登入,可以开始聊天了!");
            System.out.println("------------------------");
        } catch (UnknownHostException e) {
            System.err.println("服务器连接失败");
        } catch (IOException e) {
            System.err.println("服务器连接失败");
        }
        /**
         * 启动接收器与发送器
         */
        new Thread(new Sender(client),username).start();
        new Thread(new Receiver(client)).start();
    }
}
    //发送器:实现Runnable
    class Sender implements Runnable{
        private boolean flag = true;//服务器存活为 true
        //输出流
        private DataOutputStream dos;
        //构造器:初始化
        public Sender(Socket client) {
            try {
                dos = new DataOutputStream(client.getOutputStream());
            } catch (IOException e) {
                System.err.println("服务器未开启,连接失败");
            }
        }
        public void sendMessage() {
            Scanner scan = new Scanner(System.in);
            String message = scan.nextLine();
            try {
                dos.writeUTF(Thread.currentThread().getName()+":"+message);
                dos.flush();
            } catch (IOException e) {
                System.err.println("Sender:服务器关闭");
                flag = false;
            }
        }
        public void run() {
            while(flag) {
                sendMessage();
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    //接收器:实现Runnable
    class Receiver implements Runnable{
        private boolean flag = true;//服务器存活为 true
        //输入流
        private DataInputStream dis;
        public Receiver(Socket client) {
            try {
                dis = new DataInputStream(client.getInputStream());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        //读取消息
        public void readMessage() {
            try {
                System.out.println(dis.readUTF());
            } catch (IOException e) {
                System.err.println("Reciver:服务器关闭");
                flag =false;
            }
        }
        public void run() {
            while(flag) {
                readMessage();
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
//}

  

服务器端 代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package _20191218;
 
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
 
/**
 *  多人聊天室,服务端,实时转发数据
 */
public class TCPMultipleChatServer {
    public static void main(String[] args) {
        System.out.println("服务端开启");
        //创建服务器端
        ServerSocket server = null;
        try {
            server = new ServerSocket(6788);//服务器端口
        } catch (IOException e) {
            e.printStackTrace();
        }
        //容器
        Container container = new Container();
        //循环监听
        while(true) {
            //阻塞监听连接请求
            try {
                Socket client = server.accept();
                System.out.println("一位用户成功连接");
                container.doCount();
                //开启接收器
                new Thread(new Receiver(client,container)).start();
                //开启转发器
                new Thread(new Transmit(client,container)).start();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
     
    static class Container{
//      StringBuffer wrap = new StringBuffer();
        static int userCount = 0;//当前用户量
        private int now = 0;//已转发量
        private String[] strs = new String[1024];//消息队列
        private int i = 0;//消息计数器
        public void add(String message) {
            strs[i]=message;
            i++;
        }
        public static void doCount() {//用户量加一
            userCount++;
        }
        public void subUserCount() {//用户量减一
            userCount--;
        }
        public void reset() {
            if(now == userCount) {
                strs = new String[1024];
                now = 0;
            }
        }
    }
    static class Receiver implements Runnable{
        private boolean flag = true;
        private Container container;
        private DataInputStream dis;
        public Receiver(Socket client,Container container) {
            this.container = container;
            try {
                dis = new DataInputStream(client.getInputStream());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        //读取消息
        public void readMessage() {
            try {
                //存入容器
                String str = "";
                if(!(str = dis.readUTF()).equals("")) {
                    container.add(str);
                }
                 
            } catch (IOException e) {
                flag = false;
                System.err.println("Read:用户已离开会话");
                container.subUserCount();
            }
        }
        public void run() {
            while(flag) {
                readMessage();
            }
        }
    }
    //转发
    static class Transmit implements Runnable{
        private boolean flag = true;
        private Container container;
        private DataOutputStream dos;
        public Transmit(Socket client, Container container) {
            this.container = container;
            try {
                this.dos = new DataOutputStream(client.getOutputStream());
            } catch (IOException e) {
                flag = false;
                System.err.println("Transmit:用户已离开会话");
            }
        }
 
        public void run() {
            while(flag) {
                transmit();
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        public void transmit() {
            for(String str : container.strs) {
                try {
                    if(str==null) {
                        continue;
                    }
                    System.out.println("已转发消息:"+str);
                    container.now++;
                    dos.writeUTF(str);
                    dos.flush();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            container.reset();//转发完后清空
             
        }
    }
}

  

演示

服务器端运行一个,客户端运行多个。

posted @   Scorpicat  阅读(461)  评论(0编辑  收藏  举报
努力加载评论中...
点击右上角即可分享
微信分享提示