文本聊天室(TCP)
2018-10-19 06:30:20来源:博客园 阅读 ()
以流式的Socket实现面向连接的TCP服务
一.功能要求
1.用户可以选择聊天服务器进行登录.
2.用户使用用户名登录到聊天室,这个登录名就是用户在聊天
室的昵称.
3.可以选择群聊,广播信息,使所有用户都能看到聊天信息
4.可以选择和某个用户私聊,其他用户无法得知聊天内容.
5.聊天信息要试试反应到聊天记录中.
6.用户登录退出时,要给其他用户发出通知.
二.设计
1.界面设计
..........发挥你的想象力.........
2.整体设计
聊天室整体采用C/S模式,客户端启动后,主动向服务器发出
连接请求,建立Socket连接.服务器启动后,监听固定端口
5210,当有客户连接请求时,便响应此请求,将此连接交由线
程Talking类处理.
1.来看服务器的代码实现
1 package jffx.blogs.net;
2
3 import java.io.*;
4 import java.net.*;
5 import java.util.*;
6
7 /**
8 * 代码文件: TalkRoomServer.java
9 * 功能描述: 管理服务器与客户端的活动连接
10 */
11 public class TalkRoomServer {
12 public static void main(String[] args) {
13 try {
14 //服务器端serversocket, 绑定端口(5210), 随意选(1024后的)
15 ServerSocket server = new ServerSocket(5210);
16
17 /**
18 * 容器来保存服务器与客户端的连接, 键为姓名,值为socket
19 */
20 Map<String, Socket> socketMap = new HashMap<>() ;
21
22 while(true) {
23 //监听客户端的连接, accept的方式是阻塞的
24 try {
25 Socket ss = server.accept();
26
27 //创建流
28 //采用缓冲流,提高效率
29 DataInputStream in = new DataInputStream(
30 new BufferedInputStream(ss.getInputStream())
31 ) ;
32 DataOutputStream out = new DataOutputStream(
33 new BufferedOutputStream(ss.getOutputStream())
34 ) ;
35
36 /**
37 * 在客户端设计时,一个新的用户登录的同时就向服务器发送其姓名
38 */
39 String name = in.readUTF() ;
40 //获取IP
41 String IP = ss.getInetAddress().toString() ;
42 //显示到服务器
43 System.out.println(name + " : " + IP) ;
44
45 //查看已监听的客户,并向他们发送新用户登录消息
46 Collection<Socket> values = socketMap.values() ;
47 Iterator<Socket> iter = values.iterator() ;
48 while(iter.hasNext()) {
49 Socket temp = iter.next() ;
50 DataOutputStream write = new DataOutputStream(temp.getOutputStream()) ;
51 write.writeUTF("Add:" + name + IP) ;
52 write.flush() ;
53 }
54 //将新用户添加到容器中
55 socketMap.put(name, ss) ;
56
57 /**
58 * 向新登录的用户发送都有谁在线
59 */
60 Set<String> names = socketMap.keySet() ;
61 Iterator<String> iterName = names.iterator() ;
62 while(iterName.hasNext()) {
63 String loginUser = iterName.next() ;
64 out.writeUTF("Add:" + loginUser + IP) ;
65 out.flush() ;
66 }
67
68
69 /**
70 * 创建新线程转发用户给服务器发送的消息
71 * 由于需要分
72 * 向某个人发送消息,即:私聊
73 * 向所有发送消息,即:广播.
74 * 我们采用修改处理客户端的发送方式:
75 * 在消息的基础上,给前面即消息前缀加上一些表示发送目标的字符串.
76 * 具体看Talking.java的处理方式
77 */
78 //由于客户有可能下线,所以需要将姓名和容器都传递给线程类
79 new Thread(new Talking(name, ss, socketMap)).start() ;
80
81 } catch (Exception ex) {
82 ex.printStackTrace() ;
83 }
84 }
85 } catch (Exception ex) {
86 ex.printStackTrace() ;
87 }
88 }
89 }
下面这个是单独处理每个用户的线程代码.
大概思路是这样的:先读取这个用户的发送的消息,然后进行解析,拆分,
分情况发送给客户端;如果由用户退出了聊天室,将用户从所在的
Socket容器中剔除,并给所有客户发送这个用户退出的消息.
1 package jffx.blogs.net;
2
3 import java.io.*;
4 import java.net.*;
5 import java.util.*;
6
7 /**
8 * 代码文件:Talking.java
9 * 功能描述:线程类转发用户的数据
10 */
11 public class Talking implements Runnable {
12 String name ;
13 Socket connecter ;
14 Map<String, Socket> socketMap = null ;
15 public Talking(String name, Socket socket, Map<String, Socket> socketMap) {
16 this.name = name ;
17 this.connecter = socket ;
18 this.socketMap = socketMap ;
19 }
20
21 @Override
22 public void run() {
23 try {
24 DataInputStream in = new DataInputStream(
25 new BufferedInputStream(connecter.getInputStream())
26 ) ;
27
28 while(true) {
29 String words = in.readUTF() ;
30 /**
31 * 我们约定,客户端发送("name@text")这种格式的消息
32 * 不过用户不需要处理,我们交由客户端程序在发送消息时自动加上
33 */
34 String [] tokens = words.split("@") ;
35 String sendName = tokens[0] ;
36 String text = tokens[1] ;
37
38 if("All".equals(sendName)) {
39 //容器的值为Socket变量
40 Collection<Socket> sockets = socketMap.values() ;
41 Iterator<Socket> iter = sockets.iterator() ;
42 while(iter.hasNext()) {
43 //创建流.并以固定格式写出
44 Socket sendSocket = iter.next() ;
45 DataOutputStream out = new DataOutputStream(sendSocket.getOutputStream()) ;
46 out.writeUTF("Text:" + text) ;
47 out.flush() ;
48 }
49 } else { //私聊
50 Socket sendSocket = socketMap.get(sendName) ;
51 DataOutputStream out = new DataOutputStream(sendSocket.getOutputStream()) ;
52 out.writeUTF("Text:" + text) ;
53 out.flush() ;
54 }
55 }
56 } catch (Exception ex) {
57 ex.printStackTrace() ;
58 } finally { //当登陆的用户退出后,就会跳出while(true)
59 try {
60 /**
61 * 查找登陆的用户,删除服务器与其的连接,并发送给所有的客户端
62 */
63 this.socketMap.remove(this.name) ;
64 Collection<Socket> sockets = this.socketMap.values() ;
65 Iterator<Socket> iter = sockets.iterator() ;
66 while(iter.hasNext()) {
67 Socket sender = iter.next() ;
68 DataOutputStream out = new DataOutputStream(sender.getOutputStream()) ;
69 out.writeUTF("Del:" + this.name) ;
70 out.flush() ;
71 }
72 } catch (Exception ex) {
73 ex.printStackTrace() ;
74 }
75 }
76 }
77 }
至于客户端,留给明天.呵呵...........
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
下一篇:Java函数调用总结
- 网络编程杂谈之TCP协议 2020-05-27
- Thymeleaf读取国际化文本时出现??xxxxxx_zh_CN??问题 2020-05-19
- Java 设置PDF中的文本旋转、倾斜 2020-05-11
- 为什么 TCP 建立连接是三次握手,关闭连接确是四次挥手呢? 2020-05-06
- 轻量级富文本编辑器--wangEditor 2020-05-02
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash