090110汪锋文档格式.docx
《090110汪锋文档格式.docx》由会员分享,可在线阅读,更多相关《090110汪锋文档格式.docx(27页珍藏版)》请在冰点文库上搜索。
为实现网络聊天的功能,采用WindowsSocket编程,服务器与客户端采用了TCP/IP连接方式,在设计聊天方案时,实行将所有信息发往服务器端,再由服务器进行分别处理的思路,服务器端是所有信息的中心。
由于服务器端要保存用户信息,我们利用哈希表来实现这一功能,因此在服务器开启时需要建立用户信息对应的哈希表。
四.详细设计
客端和户服务器端的功能可划分为以下模块:
1.客户端:
(1)登陆功能:
建立与服务器的连接并登陆,能显示登陆错误信息。
(2)聊天功能:
发送消息到聊天室。
(3)退出功能:
退出与服务器的连接。
2.服务器端
(1)接受来自客户端的各种信息并分别处理。
(3)登陆信息:
检查登陆信息是否正确,并向客户端返回登陆信息,如信息正确。
就将在线用户发给该用户,并将该用户的状态发给各在线用户。
同时在服务器端显示出来。
(4)聊天信息:
转发给消息到每个用户。
(5)用户下线:
将此用户下线消息发给各客户端,并改写用户在服务器端的状态。
网络通信流程图
程序主要流程
五.源代码
服务端包含三类线程,主线程负责生成服务端窗口,并监听窗口及窗口中的按钮,ServerThread线程负责将客户机连入,ServerThreadSingle线程主要负责与客户端的通信。
代码如下:
importjava.awt.*;
importjava.awt.event.*;
import.*;
importjava.io.*;
importjava.util.Enumeration;
importjava.util.Hashtable;
importjava.util.Calendar;
publicclassServerextendsFrameimplementsActionListener{
privatebooleanserving=false;
privateColorbg=newColor(176,196,227);
privateStringrightNow;
privateInetAddresssvrAddress;
privateServerSocketserver;
privateServerThreadst;
privateHashtableht;
//记录StringuserName->
DataOutPutStreamout
//privateHashtableht_s;
Socketconnection
privateLabelsvrIP=newLabel("
ServerIP:
"
);
privateTextFieldshowSvrIP=newTextField();
privateLabelsvrPort=newLabel("
Serverport:
privateTextFieldgetSvrPort=newTextField("
8888"
privateButtonenter=newButton("
Start"
privateTextAreaoutput=newTextArea();
privateLabeluser=newLabel("
User(0)"
privateListlist=newList();
//响应关闭按钮的内部类
privateclassWindowCloserextendsWindowAdapter
{
publicvoidwindowClosing(WindowEventwe)
{
System.exit(0);
}
}
//布局设置方法,在构造方法里面调用
privatevoidsetup()
{
Paneltop=newPanel();
top.setLayout(newFlowLayout());
top.add(svrIP);
svrIP.setBackground(bg);
top.add(showSvrIP);
showSvrIP.setBackground(bg);
top.add(svrPort);
svrPort.setBackground(bg);
top.add(getSvrPort);
getSvrPort.setBackground(bg);
top.add(enter);
enter.setBackground(bg);
Paneleast=newPanel();
east.setLayout(newBorderLayout());
east.add("
North"
user);
user.setBackground(bg);
Center"
list);
list.setBackground(bg);
setLayout(newBorderLayout());
add("
top);
top.setBackground(bg);
East"
east);
east.setBackground(bg);
output);
output.setBackground(bg);
setBackground(bg);
//构造方法
publicServer()throwsUnknownHostException,IOException
super("
ChatRoomServer"
serving=false;
svrAddress=InetAddress.getLocalHost();
byte[]ip=svrAddress.getAddress();
showSvrIP.setText((ip[0]&
0xFF)+"
."
+(ip[1]&
+(ip[2]&
+(ip[3]&
0xFF));
showSvrIP.setEditable(false);
output.setEditable(false);
enter.addActionListener(this);
addWindowListener(newWindowCloser());
setup();
pack();
setSize(500,400);
show();
//用于接收客户消息的线程类
privateclassServerThreadSingleextendsThread{
publicSocketconnection;
privateDataInputStreamin;
privateDataOutputStreamout;
privatebooleanlogin;
privateStringuserName;
publicServerThreadSingle(Socket_connection){
try{
connection=_connection;
in=newDataInputStream(connection.getInputStream());
out=newDataOutputStream(connection.getOutputStream());
login=false;
userName=newString("
start();
}catch(IOExceptionioe){
output.append("
Error:
"
+ioe);
}
publicvoidrun(){
Stringline=newString("
Q"
while(!
login){
if(!
serving)break;
line=in.readUTF();
if(line.charAt(0)=='
L'
){
userName=line.substring
(2);
if(userName.length()==0){
out.writeUTF("
R"
//refused
break;
}
//判断是否已存在该用户名
for(Enumeratione=ht.keys();
e.hasMoreElements();
){
Stringstr=(String)(e.nextElement());
if(str.equalsIgnoreCase(userName)){
out.writeUTF("
//refused
return;
}
//向登陆的用户发送当前在线用户列表
login=true;
list.add(userName);
user.setText("
User("
+list.getItemCount()+"
)"
String[]str=list.getItems();
line="
A"
;
//accepted
for(inti=0;
i<
str.length;
i++){
line+=(str[i]+"
out.writeUTF(line);
L"
+userName;
rightNow=Calendar.getInstance().getTime().toLocaleString();
output.append(rightNow+"
\n"
+userName+"
login.\n\n"
//向在线用户(不包括当前客户)发送消息
for(Enumeratione=ht.elements();
DataOutputStreamout=(DataOutputStream)(e.nextElement());
out.writeUTF(line);
ht.put(userName,out);
//将登录的客户加入名单
//ht_s.put(userName,connection);
}
}
while(login){
Q'
out.writeUTF("
login=false;
ht.remove(userName);
//将退出登录的客户从名单中剔除
ht_s.remove(userName);
list.remove(userName);
Q"
else{
line=userName+"
said:
+line.substring
(2);
rightNow=Calendar.getInstance().getTime().toLocaleString();
output.append(rightNow+"
+(line.charAt(0)=='
?
userName+"
logout."
:
line)+"
\n\n"
//向所有客户发送消息
for(Enumeratione=ht.elements();
DataOutputStreamout=(DataOutputStream)(e.nextElement());
}
in.close();
out.close();
connection.close();
}catch(SocketExceptionse){
ht.remove(userName);
ht_s.remove(connection);
list.remove(userName);
Connectionto"
closed\n"
if(!
(ioeinstanceofEOFException)){
output.append("
+ioe+"
}
}
}
//用于接受客户连接请求的线程类
privateclassServerThreadextendsThread{
privatebooleanrunning;
publicServerThread()
start();
publicvoidrun()
while(serving){
Socketconnection=server.accept();
ServerThreadSinglehandler
=newServerThreadSingle(connection);
rightNow=Calendar.getInstance().getTime().toLocaleString();
output.append(rightNow+"
\nServingstoped.\n\n"
}
//消息处理方法
publicvoidactionPerformed(ActionEventevent)
if(event.getSource()==enter)
if(serving){
try{
serving=false;
ht.clear();
ht_s.clear();
list.clear();
user.setText("
server.close();
enter.setLabel("
}catch(SocketExceptionse){
}catch(IOExceptionioe){
else{
server=newServerSocket(Integer.parseInt(getSvrPort.getText()));
\nServingstarted.\n\n"
Stop"
ht=newHashtable();
//ht_s=newHashtable();
st=newServerThread();
serving=true;
//主方法
publicstaticvoidmain(Stringargs[])throwsUnknownHostException,IOException
Servers=newServer();
}
客户端主要有两个线程,主线程负责窗口布局与显示,recThread线程主要负责与服务器的通信,代码如下:
publicclassClientextendsFrameimplementsActionListener{
privatebooleanlogin=false;
privateColorbg=newColor(255,255,255);
privateInetAddressclientAddress;
privateSocketconnection;
privateDataInputStreamin;
privateDataOutputStreamout;
privaterecThreadreceiver;
privateButtonB_login=newButton("
Login"
privateButtonB_logout=newButton("
Logout"
privateButtonB_send=newButton("
Send"
privateLabeluserName=newLabel("
UserName:
privateTextFieldgetUserName=newTextField();
//获取用户名
privateTextFieldgetSvrIP=newTextField();
//获取服务器IP地址
ServerPort:
privateTextFieldgetSvrPort=newTextField();
//获取服务器端口
privateTextAreainput=newTextArea();
//输入文本框
//输出文本框
//用于接收服务器消息的线程类
privateclassrecThreadextendsThread
publicrecThread()
Stringline=in.readUTF();