📄 chatserver.java
字号:
package chatServer;
import java.net.*;
import java.sql.*;
import java.io.*;
import java.util.*;
/**
* 这个类是服务程序的主类,用来与数据库连接,负责处理用户的注册,登录检测,下线删除等数据库的操作
* 同时也是用户之间相互联系通信的桥梁.处理用户的各种请求,一对一单聊请求,群聊请求等的响应
* 所以要运行客户程序必须保证这个程序先运行起来
* @author 黄祖光
*/
public class ChatServer implements Runnable
{
public static int clientnum=10000;
public static int SERVERPORT=5566;
Connection con=null;
DatagramSocket socket=null;
boolean read=false,quited=false,isSend=false,stop=false;//isSend是用来控制群聊的发送的
Thread t=null;
String sure,addname,sendInfo;//sendInfo是用来存放新登录用户的信息的,服务程序发给每个在线用户.
InetAddress ad=null;
GroupChat grch=null;
ServerFrame sf=null;
public ChatServer()
{
try
{
socket=new DatagramSocket(SERVERPORT);
String driver="sun.jdbc.odbc.JdbcOdbcDriver";
Class.forName(driver);//建立JDBC:ODBC桥,与ACCESS数据库取得连接
t=new Thread(this);
t.start();//启动整个服务程序的主线程
sf=new ServerFrame(this);
sf.setVisible(true);
sf.setText("Server starting....");
}
catch(ClassNotFoundException ce)
{
sf.setText("Exception in sql driver");
}
catch(SocketException se)
{
se.printStackTrace();
new WarmDialog("111","Exception in register socket");
}
grch = new GroupChat();//启动群聊线程,监听用户的登录请求
}
/**
* 这个方法是主线程的方法
* 用来接收识别用户发来的信息,并做出相应的处理,处理完后再发消息给用户来确认
* 原理是通过接收用户发来的一个字符串,并把字符串分离,取出数据,然后再根据取出
* 的数据做出相应的处理,如登录,注册等.
*/
public void run()
{
try
{
while(!stop)
{
byte[] by=new byte[800];
DatagramPacket packet=new DatagramPacket(by,by.length);
socket.receive(packet);//接收用户的信息
String str=new String(packet.getData(),0,packet.getLength());//将其转化为字符串
ad=packet.getAddress();//取得用户的IP地址
int port=packet.getPort();//取得用户的端口号
StringTokenizer st=new StringTokenizer(str,"#");//分离用户发来的信息
String sign=st.nextToken();//取得标识(根据这个做出处理)
String content=st.nextToken();//分离出用户个人信息
if("REGISTER".equals(sign))//如果标识是REGISTER则是用户登录
{
SaveClient(content);//调用此方法将用户个人信息存入数据库
byte[] send=sure.getBytes();
DatagramPacket sen=new DatagramPacket(send,send.length,ad,port);
socket.send(sen);//向用户发送注册成功信息
sf.setText("a new client registered!");
}
else if("LOGIN".equals(sign))//如果标识是LOGIN则是用户登录
{
quited=false;
String s=null;
if((s=CheckInformation(content))!=null)//检测用户是否为合法用户,如果是则将其信息存入数据库并发回确认信息
{
byte[] se=("OK"+s).getBytes();
DatagramPacket pa=new DatagramPacket(se,se.length,ad,port);
socket.send(pa);//如果用户为合法用户发"OK"给用户来确认...
if(!"".equals(sendInfo))
{
grch.sm.sendString(sendInfo);//使群聊线程发信息给每一个在线用户
}
}
else//如果说为非法用户,则发回登录失败信息
{
byte[] se=("WRONG").getBytes();
DatagramPacket pa=new DatagramPacket(se,se.length,ad,port);
socket.send(pa);
}
}
else if("QUIT".equals(sign))//如果标识是QUIT,则表示用户下线,在数据库在线用户表中删除该用户,并发各在线用户发送信息
{
quited=true;//quited控制CheckInformation()方法的执行
CheckInformation(content);
byte[] sen="QUIT".getBytes();
DatagramPacket pac=new DatagramPacket(sen,sen.length,ad,port);
socket.send(pac);
sf.setText("success in sending .."+new String(pac.getData(),0,pac.getLength()));
if(!"".equals(sendInfo))
{
grch.sm.sendString(sendInfo);//使群聊线程发信息给每一个在线用户
}
}
}
}
catch(IOException ioe)
{
ioe.printStackTrace();
}
}
/**
* 这个方法用来在在线用户表中找到被请求方IP地址
* @param clientname
* @return ip
*/
public String findIP(String clientname)
{
String ip="";
String select="select IP from 在线记录表 where 用户名='"+clientname+"'";
ResultSet rs;
try
{
con =DriverManager.getConnection("jdbc:odbc:mysun","ily","8866");
Statement sql=con.createStatement();
sf.setText("This is findIP :"+clientname);
rs=sql.executeQuery(select);
if(rs.next())
{
ip=rs.getString(1);
ip=ip.substring(1,ip.length());
rs.close();
sql.close();
}
}
catch(SQLException se)
{
se.printStackTrace();
}
finally
{
try
{
con.close();
}
catch (SQLException e)
{
e.printStackTrace();
}
}
return ip;
}
/**
* 这个方法是用来处理用户注册的,通过接收一个字符串,然后分离字符串取得
* 用户的个人信息,并将其全部存入数据库中的注册表中
* @param sr
*/
public void SaveClient(String sr)
{
//boolean flag=false;
StringTokenizer stk=new StringTokenizer(sr,",");
//取得客户的注册信息并存入数据库中(表的结构为:职业,姓名,密码,账号),其中账号由服务器++生成
String work=stk.nextToken();
String name=stk.nextToken();
String password=stk.nextToken();
int num=(int) (Math.random()*clientnum);//账号可能会有重复,以后要改成用注册的时期来做为账号就不会有重复的了
String inserted="insert into 注册表 values('"+work+"','"+name+"','"+password+"',"+num+")";
try
{
con =DriverManager.getConnection("jdbc:odbc:mysun","ily","8866");
Statement sql=con.createStatement();
sql.executeUpdate(inserted);
sure="OK";//如果存入注册信息成功则给sure="OK";
sf.setText("success inserted "+num);
sql.close();
//flag=true;
}
catch(SQLException se)
{
sure="WRONG";//存入不成功则sure="WRONG";
sf.setText("exception in inserting information!!");
se.printStackTrace();
}
//return flag;
finally
{
try
{
con.close();//关闭数据库的连接
}
catch (SQLException e)
{
e.printStackTrace();
}
}
}
/**
* 这个方法有两个作用
* (1) 用来检测登录的用户是不是合法用户,如果是则将其存入数据库中,并取得在线的用户的信息发送给此用户,如果不是则拒绝登录
* (2) 当在线用户下线时,从数据库的在线用户表中移除此用户
* @param received 存放用户的个人信息
* @return 返回一个字符串
*/
public String CheckInformation(String received)//返回在线用户人数
{
StringTokenizer stk=new StringTokenizer(received,",");
int clientnum=0;
String clinf="*";//将在线的用户信息全部放到这个字符串中发给用户
ResultSet rs;
try
{
con =DriverManager.getConnection("jdbc:odbc:mysun","ily","8866");
Statement sql=con.createStatement();
if(!quited)
{
addname=stk.nextToken();
String cipher=stk.nextToken();
String select="select * from 注册表 where 姓名='"+addname+"' and 密码='"+cipher+"'";
rs=sql.executeQuery(select);
sf.setText("success selected.. ");
if(rs.next())//如果rs.next()返回TRUE 则说呀用户为合法用户,否则为非法用户
{
if(rs.getString("密码").equals(cipher)&&rs.getString("姓名").equals(addname))//在数据库中提取信息检查用户是
{ //否则为合法用户
int num=rs.getInt("账号");
clinf=clinf+num+"#";
sendInfo="ADD^"+","+num+","+ad+","+addname;//给sendInfo赋值,也就是新登录用户的信息,用以发给在线的所有用户
String check="select 账号,IP,用户名 from 在线记录表 ";
ResultSet re=sql.executeQuery(check);
while(re.next())
{//获得在线用户的信息并存入clinf中,发送给登录的用户
clinf=clinf+re.getInt(1)+",";
clinf=clinf+re.getString(2 )+",";
clinf=clinf+re.getString(3)+"#";
}
String insert="insert into 在线记录表 values("+num+",'"+ad+"','"+addname+"')";
sql.executeUpdate(insert);
sql.close();
}
else
{
System.out.println("密码或用户名错!");
}
}
else
{
clinf=null;//如果用户为非法用户则返回一个空的字符串
}
}
else//如果quited为false则是用户下线,删除其在数据库的记录( 在线用户表)
{
String name=stk.nextToken();
String select="select 账号 from 注册表 where 姓名='"+name+"'";
ResultSet r=sql.executeQuery(select);
if(r.next())
{
int aount=r.getInt(1);
String delete="delete from 在线记录表 where 用户名='"+name+"'";
sql.executeUpdate(delete);//删除用户
sf.setText(name+" success in quiting");
sendInfo="REMOVE^"+aount;//取得其帐号
}
// r.close();
sql.close();
}
}
catch(SQLException se)
{
System.out.println(se);
sf.setText("exception in select clients information!!");
}
finally
{
try
{
con.close();
}
catch (SQLException e)
{
e.printStackTrace();
}
}
return clinf;
}
/**
* 这个线程类是用来处理用户群聊
* 利用了广播数据报接收所有用户发来的信息,并将其发送给所有用户,以达到一人发送消息,所有人都能收到.
* 除了能实现群聊功能外,还实现了给所有在线用户发送新登录或下线用户的消息
* @author 黄祖光
*
*/
private class GroupChat implements Runnable //负责为客户提供群聊的类,开始....
{
String send;
byte[] rec,sen;
DatagramSocket resocket=null;
boolean stop=false;
Thread t=null;
SendMessage sm=null;
GroupChat()
{
rec=new byte[800];
try
{
resocket=new DatagramSocket(6688);
}
catch (IOException ioe)
{
ioe.printStackTrace();
new WarmDialog("socket error!","");
}
sm=new SendMessage();
sm.start();
t=new Thread(this);
t.start();
}
public void run()//利用这个线程来接收所有参加群聊的客户发来的信息
{
while(!stop)
{
try
{
DatagramPacket repacket=new DatagramPacket(rec,rec.length);
resocket.receive(repacket);
String se=new String(repacket.getData(),0,repacket.getLength());
sf.setText("server received: "+se);
StringTokenizer st=new StringTokenizer(se,"#");
String s=st.nextToken();
if("CHAT".equals(s))
{
send="CHAT^"+(st.nextToken()).trim();
isSend=true;//收到一个信息就让其为真,这样sendMessage就可以运行
}
else if("SINGLECHAT".equals(s))
{
send="SINGLECHAT^"+st.nextToken();
isSend=true;
}
}
catch(IOException e)
{
e.printStackTrace();
new WarmDialog("error in receiving..","");
}
}
}
/**
* 利用这个内部类来将接收到的信息发给全部群聊的客户(也就是内部类的内部类)
* @author 55
*
*/
private class SendMessage extends Thread
{
MulticastSocket socket=null;
InetAddress address=null;
DatagramPacket packet=null;
int port=8866;
boolean stop=false;
String str;
SendMessage()
{
try
{
socket=new MulticastSocket(8866);
address=InetAddress.getByName("239.253.253.2");
}
catch (IOException e)
{
e.printStackTrace();
}
}
public void run()
{
while(!stop)
{
try
{
if(isSend)
{
byte[] by;
by=send.getBytes();
packet=new DatagramPacket(by,by.length,address,port);
socket.send(packet);
sf.setText("groudchat sended:"+new String(packet.getData(),0,packet.getLength()));
isSend=false;//发完后就停
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
/**
* 这个方法用来给所有在线用户发送新登录用户的信息,其实也只是通过对两个变量赋值然后run()内的语句执行
* @param str
*/
public void sendString(String str)
{
send=str;
isSend=true;
}
}
}
public void close()
{
quited=false;
stop=true;
System.exit(0);
}
public static void main(String[] args)
{
ChatServer server=new ChatServer();
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -