用java socket做一个聊天室,实现多人聊天的功能。看了极客学院的视频后跟着敲的。(1day)
服务端:
1. 先写服务端的类myserversocket,里面放一个监听线程,一启动就好
2. 实现服务端监听类serverlistener.java,用accept来监听,一旦有客户端连上,生成新的socket,就新建个线程实例chatsocket。启动线程后就把线程交给chatmanager管理
3. 在chatsocket中实现从客户端读取内容,把读取到的内容发给集合内所有的客户端
4. chatmanager里面用vector来管理socket线程实例chatsocket,并实现发送信息给其他的客户端
客户端:
1. 新建一个继承jframe的mainwindow.java类,主要实现聊天窗口的ui,以及事件响应。
2. 新建startclient.java类,把mainwindow中生成mainwindow主方法部分代码拷贝过来,这样就能在主程序中把窗体执行出来了。
3. 新建chatmanager(需要单例化的类)管理socket,实现聊天的输入输出功能。最后记得在1中新建窗口后,传一份frame的引用到chatmanager中,才能实现chatmanager对界面的显示。
工程结构如图
以下为代码
服务端:
1. 先写服务端的类myserversocket,里面放一个监听线程,一启动就好
1
2
3
4
5
6
7
8
|
package com.starnet.testserversocket.main;
public class myserversocket {
public static void main(string[] args) {
new serverlistener().start();
}
}
|
2.实现服务端监听类serverlistener.java,用accept来监听,一旦有客户端连上,生成新的socket,就新建个线程实例chatsocket。启动线程后就把线程交给chatmanager管理
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
|
package com.starnet.testserversocket.main;
import java.io.ioexception;
import java.net.serversocket;
import java.net.socket;
import javax.swing.joptionpane;
public class serverlistener extends thread {
public void run() {
try {
serversocket serversocket = new serversocket( 23456 );
while ( true ) {
// block
socket socket = serversocket.accept();
// 建立链接
joptionpane.showmessagedialog( null , "有客户端连到本机23456端口" );
//将socket传递给新的线程
chatsocket cs= new chatsocket(socket);
cs.start();
chatmanager.getchatmanager().add(cs);
}
} catch (ioexception e) {
e.printstacktrace();
}
}
}
|
3.在chatsocket中实现从客户端读取内容,把读取到的内容发给集合内所有的客户端
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
|
package com.starnet.testserversocket.main;
import java.io.bufferedreader;
import java.io.ioexception;
import java.io.inputstreamreader;
import java.io.unsupportedencodingexception;
import java.net.socket;
/*每一个连上的客户端,服务器都有一个线程为之服务*/
public class chatsocket extends thread {
socket socket;
public chatsocket(socket s) {
this .socket = s;
}
//发送数据
public void out(string out) {
try {
socket.getoutputstream().write(out.getbytes( "utf-8" ));
} catch (unsupportedencodingexception e) {
// todo auto-generated catch block
e.printstacktrace();
} catch (ioexception e) {
// todo auto-generated catch block
e.printstacktrace();
}
}
//服务器会不断地从客户端读取内容,把读取到的内容发给集合内所有的客户端。
public void run() {
try {
//接收数据
bufferedreader br = new bufferedreader(
new inputstreamreader(
socket.getinputstream(), "utf-8" ));
string line= null ;
//发送读到的内容
while ((line = br.readline())!= null ) {
system.out.println(line);
chatmanager.getchatmanager().publish( this , line);
}
br.close();
} catch (ioexception e) {
// todo auto-generated catch block
e.printstacktrace();
}
}
}
|
4.chatmanager里面用vector来管理socket线程实例chatsocket,并实现发送信息给其他的客户端
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
|
package com.starnet.testserversocket.main;
import java.util.vector;
//一个聊天服务器只能有一个manager,要单例化处理
public class chatmanager {
private chatmanager(){}
private static final chatmanager cm= new chatmanager();
public static chatmanager getchatmanager(){
return cm;
}
vector<chatsocket> vector = new vector<chatsocket>();
/*增加chatsocket 实例到vector中*/
public void add(chatsocket cs){
vector.add(cs);
}
/*发布消息给其他客户端
*chatsocket cs: 调用publish的线程
*msg:要发送的信息 */
public void publish(chatsocket cs, string msg){
for ( int i = 0 ; i < vector.size(); i++) {
chatsocket cstemp = vector.get(i);
if (!cs.equals(cstemp)) {
cstemp.out(msg+ "\n" ); //不用发送给自己。
}
}
}
}
|
客户端:
1. 新建一个继承jframe的mainwindow.java类,主要实现聊天窗口的ui,以及事件响应。
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
|
package com.starnet.javaclient.view;
import java.awt.borderlayout;
import java.awt.eventqueue;
import javax.swing.jframe;
import javax.swing.jpanel;
import javax.swing.border.emptyborder;
import javax.swing.jtextarea;
import javax.swing.grouplayout;
import javax.swing.grouplayout.alignment;
import javax.swing.jtextfield;
import javax.swing.jbutton;
import javax.swing.layoutstyle.componentplacement;
import com.starnet.javaclient.main.chatmanager;
import com.sun.xml.internal.ws.client.senderexception;
import java.awt.event.mouseadapter;
import java.awt.event.mouseevent;
public class mainwindow extends jframe {
/**
*
*/
private static final long serialversionuid = 1l;
private jpanel contentpane;
private jtextarea txt;
private jtextfield txtip;
private jtextfield txtsend;
/**
* create the frame.
*/
public mainwindow() {
setalwaysontop( true );
setdefaultcloseoperation(jframe.exit_on_close);
setbounds( 100 , 100 , 450 , 300 );
contentpane = new jpanel();
contentpane.setborder( new emptyborder( 5 , 5 , 5 , 5 ));
setcontentpane(contentpane);
txt = new jtextarea();
txt.settext( "ready..." );
txtip = new jtextfield();
txtip.settext( "127.0.0.1" );
txtip.setcolumns( 10 );
jbutton btnconnect = new jbutton( "connect" );
btnconnect.addmouselistener( new mouseadapter() {
@override
public void mouseclicked(mouseevent e) {
chatmanager.getchatmanager().connect(txtip.gettext());
}
});
txtsend = new jtextfield();
txtsend.settext( "hello" );
txtsend.setcolumns( 10 );
jbutton btnsend = new jbutton( "send" );
btnsend.addmouselistener( new mouseadapter() {
@override
public void mouseclicked(mouseevent e) {
chatmanager.getchatmanager().send(txtsend.gettext());
appendtext( "我说: " +txtsend.gettext());
txtsend.settext( "" );
}
});
grouplayout gl_contentpane = new grouplayout(contentpane);
gl_contentpane.sethorizontalgroup(
gl_contentpane.createparallelgroup(alignment.leading)
.addgroup(alignment.trailing, gl_contentpane.createsequentialgroup()
.addgroup(gl_contentpane.createparallelgroup(alignment.trailing)
.addgroup(gl_contentpane.createsequentialgroup()
.addcomponent(txtsend, grouplayout.default_size, 325 , short .max_value)
.addpreferredgap(componentplacement.related)
.addcomponent(btnsend, grouplayout.preferred_size, 109 , grouplayout.preferred_size))
.addgroup(alignment.leading, gl_contentpane.createsequentialgroup()
.addcomponent(txtip, grouplayout.preferred_size, 294 , grouplayout.preferred_size)
.addpreferredgap(componentplacement.related)
.addcomponent(btnconnect, grouplayout.default_size, 140 , short .max_value))
.addcomponent(txt, grouplayout.default_size, 434 , short .max_value))
.addcontainergap())
);
gl_contentpane.setverticalgroup(
gl_contentpane.createparallelgroup(alignment.leading)
.addgroup(gl_contentpane.createsequentialgroup()
.addgroup(gl_contentpane.createparallelgroup(alignment.baseline)
.addcomponent(txtip, grouplayout.preferred_size, grouplayout.default_size, grouplayout.preferred_size)
.addcomponent(btnconnect))
.addpreferredgap(componentplacement.related)
.addcomponent(txt, grouplayout.default_size, 198 , short .max_value)
.addpreferredgap(componentplacement.related)
.addgroup(gl_contentpane.createparallelgroup(alignment.trailing)
.addcomponent(btnsend)
.addcomponent(txtsend, grouplayout.preferred_size, grouplayout.default_size, grouplayout.preferred_size)))
);
contentpane.setlayout(gl_contentpane);
}
/*客户端发送的内容添加到中间的txt控件中*/
public void appendtext(string in) {
txt.append( "\n" + in);
}
}
|
2.新建startclient.java类,把mainwindow中生成mainwindow主方法部分代码拷贝过来,这样就能在主程序中把窗体执行出来了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
package com.starnet.javaclient.main;
import java.awt.eventqueue;
import com.starnet.javaclient.view.mainwindow;
public class startclient {
public static void main(string[] args) {
/*先新建一个jframe,然后把自动生成的代码贴过来*/
eventqueue.invokelater( new runnable() {
public void run() {
try {
mainwindow frame = new mainwindow();
frame.setvisible( true );
//创建完这个frame以后,传一份window的引用到chatmanager去
chatmanager.getchatmanager().setwindow(frame);
} catch (exception e) {
e.printstacktrace();
}
}
});
}
}
|
3.新建chatmanager(需要单例化的类)管理socket,实现聊天的输入输出功能。最后记得在1中新建窗口后,传一份frame的引用到chatmanager中,才能实现chatmanager对界面的显示。
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
|
package com.starnet.javaclient.main;
import java.io.bufferedreader;
import java.io.ioexception;
import java.io.inputstreamreader;
import java.io.outputstreamwriter;
import java.io.printwriter;
import java.net.socket;
import java.net.unknownhostexception;
import com.starnet.javaclient.view.mainwindow;
public class chatmanager {
private chatmanager(){}
private static final chatmanager instance= new chatmanager();
public static chatmanager getchatmanager(){
return instance;
}
mainwindow window; //为了能在界面上显示服务器发来的信息,就需要传一个mainwindow的引用进来
socket socket;
private string ip;
bufferedreader breader;
printwriter pwriter;
public void setwindow(mainwindow window) {
this .window = window;
window.appendtext( "文本框已经和chatmanager绑定了" );
}
public void connect(string ip) {
this .ip = ip;
new thread(){
@override
public void run() {
//实现网络方法
try {
socket = new socket(ip, 23456 );
//输出流
pwriter = new printwriter(
new outputstreamwriter(
socket.getoutputstream()));
//输入流
breader = new bufferedreader(
new inputstreamreader(
socket.getinputstream()));
string line = null ;
//如果读取数据为空
while ((line = breader.readline())!= null ) {
window.appendtext( "收到: " +line);
}
//读完数据之后要关闭
pwriter.close();
breader.close();
pwriter = null ;
breader = null ;
} catch (unknownhostexception e) {
e.printstacktrace();
} catch (ioexception e) {
e.printstacktrace();
}
}
}.start();
}
public void send(string sendmsg){
if (pwriter!= null ) {
pwriter.write(sendmsg+ "\n" );
pwriter.flush();
} else {
window.appendtext( "当前链接已经中断..." );
}
}
}
|
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/u013427822/article/details/54947649