上篇介绍了java基于c/s模式实现聊天程序的客户端写法,这一篇介绍服务器的写法。
服务器的功能是:接收来自客户端的消息,然后将消息转发给当前连接的所有用户。这里一个困扰我许久的地方是如何存储所有用户的地址(套接字),找了许久我找到了一种变长数组的数据结构vector,用size()来获取长度,用add()来添加元素,这样就容易多了,解决了服务器最大的问题。
服务器我定义了一个启动服务器的按钮,通过此按钮可以启动服务器的监听线程,我把服务器的创建放在了监听线程中。
服务器主要由两个线程组成:监听和消息处理。
监听线程:建立服务器的套接字,接收来自客户端的连接,每当有客户端连接到服务器时,服务器都要把该客户端的套接字添加到变长数组socketsss中,并且要给每个用户都创建单独的线程。
消息处理线程:在输入流中读取来自客户端的utf字符串,然后遍历vector数组socketsss,将utf字符串写入到对每一个用户的输出流中。
服务器的功能就是这些了,这样就能实现基本的聊天室功能了,感觉最难的地方就是消息转发了,不过最后找到了合适的方法也解决了。只有当自己动手去写了才会发现自己有什么地方的不足,比如,设置关闭按钮的响应时,在弹出的对话框中点什么都关闭,后来发现是前面窗体设置关闭没有改成无操作;还有就是刚开始服务器只能接收处理一组消息,第二组就出问题了,是因为我以为把监听写到线程中就可以无限调用了,还是要把他放到循环中去。总之,纸上得来终觉浅绝知此事要躬行,凡事动手去做比看书理解要深刻,学编程还是要多动动手。
界面展示:
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
|
package server; import java.awt.*; import java.io.*; import java.net.*; import java.util.*; import java.awt.event.*; import javax.swing.*; public class server extends jframe { jtextarea textshow; jbutton start; vector socketsss = new vector(); //这里用到了变长对象数组,用来存储来自客户端的socket对象 serversocket server = null ; socket clients; server() { // 服务器的构造函数,并且初始化 init(); setvisible( true ); setdefaultcloseoperation(jframe.do_nothing_on_close); setbounds( 450 , 150 , 340 , 455 ); settitle( "好好学习天天向上聊天室服务器" ); setresizable( false ); } void init() { // 设置布局和事件监视器 setlayout( new flowlayout()); getcontentpane().setbackground( new color( 20 , 85 , 237 )); textshow = new jtextarea( 21 , 29 ); textshow.setbackground( new color( 45 , 210 , 209 )); start = new jbutton( " 启动服务器 " ); start.setbackground( new color( 236 , 134 , 21 )); add(start); add( new jscrollpane(textshow)); textshow.seteditable( false ); start.addactionlistener( new actionlistener() { public void actionperformed(actionevent e) { //在这里启动监听的线程 listen listen = new listen(); thread go = new thread(listen); go.start(); } }); addwindowlistener( new windowadapter() { // 响应关闭按钮功能 public void windowclosing(windowevent e) { int option = joptionpane .showconfirmdialog( null , "亲爱的你真的要离开聊天室么?" , " 好好学习天天向上聊天室" , joptionpane.yes_no_option, joptionpane.question_message); if (option == joptionpane.yes_option) system.exit( 0 ); } }); } // init()结束 class serverthread extends thread { // 服务器消息处理的线程 socket socket; dataoutputstream out = null ; datainputstream in = null ; string s = null ; vector sockets = new vector(); int j = 0 ; serverthread(socket t, vector socketss) { socket = t; sockets = socketss; try { in = new datainputstream(socket.getinputstream()); } catch (ioexception e) { } } public void run() { while ( true ) { try { string r = in.readutf(); // 堵塞状态,除非读取到信息 for ( int j = 0 ; j < sockets.size(); j++) { out = new dataoutputstream( ((socket) sockets.get(j)).getoutputstream()); // 对于每个数组内的socket对象都建立输出流 out.writeutf(r); } } catch (ioexception e) { textshow.append( "有一个逗比离开了\n" ); return ; } } } } class listen implements runnable { // 服务器监听线程 serversocket server; socket clients; public void run() { while ( true ) { try { server = new serversocket( 8888 ); textshow.append( new java.text.simpledateformat( "yy-mm-dd hh:mm:ss" ).format( new date()) + "服务器已开启\n" ); } catch (ioexception e1) { textshow.append( "正在监听\n" ); // serversocket对象不能重复创建 } try { textshow.append( new java.text.simpledateformat( "yy-mm-dd hh:mm:ss" ).format( new date()) + " 等待用户连接......\n" ); clients = server.accept(); socketsss.add(clients); serverthread handlers = new serverthread(clients, socketsss); handlers.start(); // 为每个用户创建单独的消息处理线程 textshow.append( new java.text.simpledateformat( "yy-mm-dd hh:mm:ss" ).format( new date()) + "有用户连接,用户的地址:" + clients.getinetaddress() + "\n" ); } catch (ioexception e1) { textshow.append( new java.text.simpledateformat( "yy-mm-dd hh:mm:ss" ).format( new date()) + "正在等待逗比来临......\n" ); } } } } public static void main(string args[]) { server server = new server(); } } |
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家,关注服务器之家公众号的更多精彩内容。
原文链接:https://blog.csdn.net/h843653844/article/details/50412491