1、基于 JAVA 的聊天(ICQ)系统的设计于实现指导教师: 学号: 地址: 邮编: 摘要:随着 JAVA 语言越来越受到程序员的青睐,JAVA 语言有着极其广阔的发展潜力,本系统是采用 JAVA 语言编写的聊天系统,做为学习JAVA 语言的上机的一次锻炼。关键词:JAVA 聊天系统,ICQ 系统,聊天系统。内容:分析聊天(ICQ)系统,并尝试用 Java 编写。 (备注:本系统部分代码来源与参考文献)一序言ICQ 是英文“I seek you “的简称,中文意思是我找你。ICQ 最大的功能就是即时信息交流,只要记得对方的号码,上网时可以呼他,无论他在哪里,只要他上网打开 ICQ,人们就可以随时
2、交流。ICQ 源于以色列特拉维夫的 Mirabils 公司。该公司成立于年月,也就是在这个时候,互联网上最出名,下载使用人数最多的免费软件 ICQ 诞生了。可能是其不断增加的用户和广阔的前景以及广泛的应用前景和巨大的市场潜力,Mirabils 的 ICQ 最终被美国在线 AOL 收购。由于 ICQ 的成功,推动了ICQ 的本土化,就中文的 ICQ 而言,现在已经越来越多,比如著名的深圳腾迅公司推出的 OICQ(现在由于版权问题,已改名为 QQ2001),还有由 TOM.COM 推出的Tomq 等,这些软件技术都很好,而且简单易用,成为中国网民最喜欢的通信软件。但是这些公司都只提供软件的客户端程
3、序免费下载,而不提供其服务器程序,因此对于未与互联网连接的私有网络,这些软件就用不上了。当然网上也有免费的类似 ICQ的服务器提供下载,但是好多都不提供源程序,即使有,其说明也很简单,我很想知道它是怎么回事,所以我就试着做了。二设计为什么选择 JAVA?Java 是 Sun Microsystem 公司的 James Gosling 开发的编程语言。它以 C+为基础,但是却是一个全新的软件开发语言。Java 是一个简单,面象对象,分布式,解释性,强壮,安全,与系统无关,可移植,高性能,多线程和动态的语言-这是 Sun 给Java 的定义。Sun 公司的口号就是“网络就是计算机“,Java 能使
4、所有东西从桌面计算平稳的转变为基于网络的计算,它是专门为此而建立的,并显然是为了完成这个任务而来的。使用Java,我们可以相对轻松的一天编写一个有条理的网络程序。今天,Java 的网络功能正在飞跃发展,不断有新的特性增加到这个有价值的基础上,JavaSoft 实验室正在不断努力使 Java 更加完善。2数据库设计系统可以采用任何一种流行的,Java 支持的数据库,本系统采用了 Microsoft 公司的SQL Server2000 作为后台数据库。通过对现在流行的一些 Icq 的参考,建立数据库,名为 javaicq,数据库共建立两个表,一个是用户的基本信息,包括呢称,Jicq 号码等。一个是
5、用户的好友表,包括用户自己的号码和好友的号码。(1)用户的基本信息表(表名 icq)序号 字段名 含义 数据类型 NULL1 Icqno 用户的号码 int No2 Nickname 用户的呢称 Char No3 Password 用户的密码 Char No4 Status 用户在线否 Bit No5 Ip 用户的 IP 地址 Char Yes6 Info 用户的资料 Varchar Yes7 Pic 用户的头像号 Int Yes8 Sex 用户性别 Char Yes9 Email 用户的 email Char Yes10 Place 用户的籍贯 Char yes其中 Icqno 字段为自动增
6、加。 (其他还可以添加诸如电话号码等字段作为更多选择)(2)用户的好友表(表名 friend)序号 字段名 含义 数据类型 NULL1 Icqno 用户的号码 Int No2 Friend 好友的号码 Int No3系统模式及程序 (具体程序参看源程序)系统采用客户/服务器摸式(如图)1. 服务器程序: 服务器与客户间通过套接口 Socket(TCP)连接。在 java 中使用套接口相当简单,Java API 为处理套接口的通信提供了一个类 .Socket.,使得编写网络应用程序相对容易服务器采用多线程以满足多用户的请求,通过 JDBC 与后台数据库连接,并通过创建一个 ServerSocke
7、t 对象来监听来自客户的连接请求,默认端口为 8080,然后无限循环调用 accept()方法接受客户程序的连接服务器程序代码如下:(部分)import java.io.*;import .*;import java.sql.*;import java.util.Vector;class ServerThread extends Thread/继承线程private Socket socket;/定义套接口private BufferedReader in;/定义输入流private PrintWriter out;/定义输出流int no;/定义申请的 jicq 号码public Serve
8、rThread(Socket s) throws IOException /线程构造函数socket=s;/取得传递参数in=new BufferedReader(new InputStreamReader(socket.getInputStream();/创建输入流out=new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(),true);/创建输出流start();/启动线程public void run()/线程监听函数try while(true)String str=in.r
9、eadLine();/取得输入字符串if(str.equals(“end“)break;/如果是结束就关闭连接else if(str.equals(“login“) /如果是登录try Class.forName(“sun.jdbc.odbc.JdbcOdbcDriver“);/连接数据库Connection c=DriverManager.getConnection(“jdbc:odbc:javaicq“,“ “,“ “);String sql=“select nickname,password from icq where icqno=?“;/准备从数据库选择呢称和密码PreparedSt
10、atement prepare=c.prepareCall(sql);/设定数据库查寻条件String icqno=in.readLine();int g=Integer.parseInt(icqno);/取得输入的 jicq 号码System.out.println(icqno);String passwd=in.readLine().trim();/取得输入的密码System.out.println(passwd);prepare.clearParameters();prepare.setInt(1,g);/设定参数ResultSet r=prepare.executeQuery();/执
11、行数据库查寻if(r.next()/以下比较输入的号码于密码是否相同String pass=r.getString(“password“).trim();System.out.println(pass);if(passwd.regionMatches(0,pass,0,pass.length() out.println(“ok“);/如果相同就告诉客户 ok/并且更新数据库用户为在线/以及注册用户的 ip 地址/*register ipaddressString setip=“update icq set ip=? where icqno=?“;PreparedStatement prest=
12、c.prepareCall(setip);prest.clearParameters();prest.setString(1,socket.getInetAddress().getHostAddress();prest.setInt(2,g);int set=prest.executeUpdate();System.out.println(set);/*ipaddress/set status onlineString status=“update icq set status=1 where icqno=?“;PreparedStatement prest2=c.prepareCall(st
13、atus);prest2.clearParameters();prest2.setInt(1,g);int set2=prest2.executeUpdate();System.out.println(set2);/set online/否者告诉客户失败else out.println(“false“);r.close();c.close();else out.println(“false“);System.out.println(“false“);r.close();c.close();catch (Exception e)e.printStackTrace();socket.close()
14、;/end login/登录结束/以下为处理客户的新建请求else if(str.equals(“new“)try Class.forName(“sun.jdbc.odbc.JdbcOdbcDriver“);/连接数据库Connection c2=DriverManager.getConnection(“jdbc:odbc:javaicq“,“ “,“ “);String newsql=“insert into icq(nickname,password,email,info,place,pic) values(?,?,?,?,?,?)“;/准备接受用户的呢称,密码,email,个人资料,籍贯
15、,头像等信息PreparedStatement prepare2=c2.prepareCall(newsql);String nickname=in.readLine().trim();String password=in.readLine().trim();String email=in.readLine().trim();String info=in.readLine().trim();String place=in.readLine().trim();int picindex=Integer.parseInt(in.readLine();prepare2.clearParameters(
16、);prepare2.setString(1,nickname);prepare2.setString(2,password);prepare2.setString(3,email);prepare2.setString(4,info);prepare2.setString(5,place);prepare2.setInt(6,picindex);int r3=prepare2.executeUpdate();/执行数据库添加String sql2=“select icqno from icq where nickname=?“;/以下告诉客户其注册的号码PreparedStatement p
17、repare3=c2.prepareCall(sql2);prepare3.clearParameters();prepare3.setString(1,nickname);ResultSet r2=prepare3.executeQuery();while(r2.next()/out.println(r2.getInt(1);no=r2.getInt(1);System.out.println(no);out.println(no);out.println(“ok“);c2.close();/完毕catch (Exception e)e.printStackTrace();out.print
18、ln(“false“);socket.close();/end new/新建用户结束/以下处理用户查找好友else if(str.equals(“find“)try Class.forName(“sun.jdbc.odbc.JdbcOdbcDriver“);Connection c3=DriverManager.getConnection(“jdbc:odbc:javaicq“,“ “,“ “);/以下连接数据库,并且返回其他用户的呢称,性别,籍贯,个人资料等信息String find=“select nickname,sex,place,ip,email,info from icq“;Sta
19、tement st=c3.createStatement();ResultSet result=st.executeQuery(find);while(result.next()out.println(result.getString(“nickname“);out.println(result.getString(“sex“);out.println(result.getString(“place“);out.println(result.getString(“ip“);out.println(result.getString(“email“);out.println(result.getS
20、tring(“info“);/while endout.println(“over“);/GET ICQNOint d,x;boolean y;/以下返回用户的 jicq 号码,头像号,及是否在线ResultSet iset=st.executeQuery(“select icqno,pic,status from icq“);while(iset.next()d=iset.getInt(“icqno“);out.println(d);x=iset.getInt(“pic“);/pic infoout.println(x);y=iset.getBoolean(“status“);if (y)o
21、ut.println(“1“);else out.println(“0“);/System.out.println(d);/ end send jicqnoiset.close();/icqno endc3.close();result.close();catch (Exception e)e.printStackTrace();System.out.println(“false“);/socket.close();/end find/查找好友结束/以下处理用户登录时读取其好友资料else if(str.equals(“friend“)try Class.forName(“sun.jdbc.o
22、dbc.JdbcOdbcDriver“);Connection c4=DriverManager.getConnection(“jdbc:odbc:javaicq“,“ “,“ “);/以下连接好友表,返回用户的好友名单String friend=“select friend from friend where icqno=?“;PreparedStatement prepare4=c4.prepareCall(friend);prepare4.clearParameters();int icqno=Integer.parseInt(in.readLine();System.out.print
23、ln(icqno);prepare4.setInt(1,icqno);ResultSet r4=prepare4.executeQuery();Vector friendno=new Vector();/该矢量保存好友号码while(r4.next()friendno.add(new Integer(r4.getInt(1);/read friend info/以下告诉客户其好友的呢称,号码,ip 地址,状态,头像,个人资料等信息out.println(friendno.size();for(int i=0;ifriendno.size();i+)String friendinfo=“sele
24、ct nickname,icqno,ip,status,pic,email,info from icq where icqno=?“;PreparedStatement prepare5=c4.prepareCall(friendinfo);prepare5.clearParameters();prepare5.setObject(1,friendno.get(i);ResultSet r5=prepare5.executeQuery();boolean status;while(r5.next()out.println(r5.getString(“nickname“);out.println
25、(r5.getInt(“icqno“);out.println(r5.getString(“ip“);status=r5.getBoolean(“status“);if (status)out.println(“1“);else out.println(“0“);out.println(r5.getInt(“pic“);out.println(r5.getString(“email“);out.println(r5.getString(“info“); /whiler5.close();/for/发送完毕out.println(“over“);System.out.println(“over“
26、);c4.close();r4.close();catch (Exception e)e.printStackTrace();System.out.println(“false“);/socket.close();/end friend/读取好友信息完毕/以下处理用户添加好友else if(str.equals(“addfriend“)System.out.println(“add“);try Class.forName(“sun.jdbc.odbc.JdbcOdbcDriver“);Connection c6=DriverManager.getConnection(“jdbc:odbc:ja
27、vaicq“,“ “,“ “);/连接数据库,根据接受的用户号码及好友号码向好友表添加记录int friendicqno=Integer.parseInt(in.readLine();System.out.println(friendicqno);int myicqno=Integer.parseInt(in.readLine();System.out.println(myicqno);String addfriend=“insert into friend values(?,?)“;PreparedStatement prepare6=c6.prepareCall(addfriend);pr
28、epare6.clearParameters();prepare6.setInt(1,myicqno);prepare6.setInt(2,friendicqno);int r6=0;r6=prepare6.executeUpdate();if(r6=1) System.out.println(“ok addfrien“);else System.out.println(“false addfriend“);catch (Exception e)e.printStackTrace();System.out.println(“false“);/socket.close();System.out.
29、println(“over addfriend“);/end addfriend/用户添加好友结束/add new friend who add me/以下处理其他用户如果加我,我就加他else if(str.equals(“addnewfriend“)System.out.println(“add“);try Class.forName(“sun.jdbc.odbc.JdbcOdbcDriver“);Connection c6=DriverManager.getConnection(“jdbc:odbc:javaicq“,“ “,“ “);/连接数据库,根据接受的用户号码及好友号码向好友表添
30、加记录int friendicqno=Integer.parseInt(in.readLine();System.out.println(friendicqno);int myicqno=Integer.parseInt(in.readLine();System.out.println(myicqno);String addfriend=“insert into friend values(?,?)“;PreparedStatement prepare6=c6.prepareCall(addfriend);prepare6.clearParameters();prepare6.setInt(1
31、,myicqno);prepare6.setInt(2,friendicqno);int r6=0;r6=prepare6.executeUpdate();if(r6=1) System.out.println(“ok addfrien“);else System.out.println(“false addfriend“);String friendinfo=“select nickname,icqno,ip,status,pic,email,info from icq where icqno=?“;/如果成功,就向用户传递好友的基本信息,比如呢称等PreparedStatement pre
32、pare5=c6.prepareCall(friendinfo);prepare5.clearParameters();prepare5.setInt(1,friendicqno);ResultSet r5=prepare5.executeQuery();boolean status;while(r5.next()System.out.println(“dsf“);out.println(r5.getString(“nickname“);out.println(r5.getInt(“icqno“);out.println(r5.getString(“ip“);status=r5.getBool
33、ean(“status“);if (status)out.println(“1“);else out.println(“0“);out.println(r5.getInt(“pic“);out.println(r5.getString(“email“);out.println(r5.getString(“info“); /whileout.println(“over“);r5.close();c6.close();catch (Exception e)e.printStackTrace();System.out.println(“false“);System.out.println(“over
34、 addnewfriend“);/end addfriend/结束处理其他用户如果加我,我就加他/delete friend/以下执行用户删除好友else if(str.equals(“delfriend“)System.out.println(“del“);try Class.forName(“sun.jdbc.odbc.JdbcOdbcDriver“);Connection c7=DriverManager.getConnection(“jdbc:odbc:javaicq“,“ “,“ “);/连接数据库,根据接受的用户号码及好友号码向好友表删除记录int friendicqno=Inte
35、ger.parseInt(in.readLine();System.out.println(friendicqno);int myicqno=Integer.parseInt(in.readLine();System.out.println(myicqno);String addfriend=“delete from friend where icqno=? and friend=?“;PreparedStatement prepare7=c7.prepareCall(addfriend);prepare7.clearParameters();prepare7.setInt(1,myicqno
36、);prepare7.setInt(2,friendicqno);int r7=0;r7=prepare7.executeUpdate();if(r7=1) System.out.println(“ok delfrien“);/成功else System.out.println(“false delfriend“);/失败catch (Exception e)e.printStackTrace();System.out.println(“del false“);/end delete friend/执行用户删除好友结束/以下处理用户退出程序else if(str.equals(“logout“
37、)try Class.forName(“sun.jdbc.odbc.JdbcOdbcDriver“);Connection c8=DriverManager.getConnection(“jdbc:odbc:javaicq“,“ “,“ “);/连接数据库,根据接受的用户号码,将其状态字段设为 0,及 ip 地址设为空int myicqno=Integer.parseInt(in.readLine();System.out.println(myicqno);String status=“update icq set status=0 , ip= where icqno=?“;PreparedS
38、tatement prest8=c8.prepareCall(status);prest8.clearParameters();prest8.setInt(1,myicqno);int r8=prest8.executeUpdate();if(r8=1) System.out.println(“ok logout“);else System.out.println(“false logout“);catch (Exception e)e.printStackTrace();System.out.println(“logout false“);/logout end/处理用户退出程序结束/get
39、 who add me as friend/以下处理那些人加了我为好友,以便上线通知他们else if(str.equals(“getwhoaddme“)System.out.println(“getwhoaddme“);try Class.forName(“sun.jdbc.odbc.JdbcOdbcDriver“);Connection c9=DriverManager.getConnection(“jdbc:odbc:javaicq“,“ “,“ “);/连接数据库,根据我的号码,从好友表中选择谁加了我int myicqno=Integer.parseInt(in.readLine();
40、System.out.println(myicqno);String getwhoaddme=“select icqno from friend where friend=?“;PreparedStatement prepare6=c9.prepareCall(getwhoaddme);prepare6.clearParameters();prepare6.setInt(1,myicqno);ResultSet r6=prepare6.executeQuery();Vector who=new Vector();while(r6.next()who.add(new Integer(r6.get
41、Int(1);/end while/然后告诉这些好友的 ip 地址,然后发给用户以便告诉其他客户我上线了for(int i=0;iwho.size();i+)String whoinfo=“select ip from icq where icqno=? and status=1“;PreparedStatement prepare=c9.prepareCall(whoinfo);prepare.clearParameters();prepare.setObject(1,who.get(i);ResultSet r=prepare.executeQuery();while(r.next()ou
42、t.println(r.getString(“ip“); /whiler.close();/forout.println(“over“);System.out.println(“over“);c9.close();r6.close();catch (Exception e)e.printStackTrace();System.out.println(“false“);/end get who add me as friend/处理上线结束System.out.println(“Echo ing :“+str); System.out.println(“Close.“);catch(IOExce
43、ption e)/捕或异常finally trysocket.close();catch(IOException e)public class Server/主服务器类public static void main(String args)throws IOExceptionServerSocket s=new ServerSocket(8080);/在 8080 端口创建套接口System.out.println(“Server start“+s);trywhile(true)Socket socket=s.accept();/无限监听客户的请求System.out.println(“Con
44、nectino accept:“+socket);trynew ServerThread(socket);/创建新线程catch(IOException e)socket.close();finallys.close();/捕或异常/服务器程序结束2. 客户程序如下(部分) 客户通过 Socket(InetAddress,port)建立与服务器的连接。服务器与客户都通过构造 BufferedReader,PrintWriter 来建立输入输出流,然后双方通过该输入输出流来相互传递信息,一旦收到客户方的连接请求,服务器 accept()方法返回一个新建的 Socket 对象。客户端然后向服务器发
45、送消息,比如注册,登录,查找好友等,服务器收到来自客户的请求后,针对不同的消息处理请求, 虽然 UDP不可靠但是对于 icq 可靠性并不太重要,而且 UDP 快速,所以客户间发送信息通过 UDP。用户登录时通过类 DatagramPacket 和 DatagramSocket 创建UDP 包括其本地接受端口以及发送端口,默认端口为 5000 和 5001,通过取得的好友的 IP 地址来向好友发送消息(send(DatagramPacket)和接受消息(receive(DatagramPacket)。当用户通过 UDP 收到消息后,可以通过DatagramPacket 的方法 InetAddre
46、ss getAddress()得到对方的 ip 地址,通过对好友列表比较以判断是谁并提示用户收到某某的消息,然后用户选择该用户查看消息,如果好友列表没有该人就显示收到陌生人的消息。用户可以按陌生人按钮查看消息。1. 用户注册。当服务器收到用户的注册请求,便开始接受客户传第的信息,诸如客户的呢称啦,性别,籍贯,头像,个人资料等,接受完毕后,便通过 JdbcOdbc 与后台数据库连接,然后向数据库添加记录,如果成功,便向客户返回其 Jicq 号码,并在数据库中注册用户的 IP 地址,然后更新其 Status 为 1 即用户在线。客户收到服务器返回的信息后,便打开主程序窗口,并同时开始创建 UDP
47、以便在用户之间建立联系。 *部分程序如下:void jButton1_mouseClicked(MouseEvent e) trySocket socket=new Socket(InetAddress.getByName(sername),serverport);/连接服务器BufferedReader in=new BufferedReader(new InputStreamReader(socket.getInputStream();PrintWriter out=new PrintWriter(new BufferedWriter(new OutputStreamWriter(sock
48、et.getOutputStream(),true);out.println(“new“);/告诉服务器我要注册out.println(nickname.getText().trim();/告诉服务器我的呢称,密码,email,资料out.println(password.getPassword();/以及头像号等信息out.println(email.getText().trim();out.println(info.getText().trim();out.println(place.getSelectedItem();out.println(headpic.getSelectedIndex();/head picindexint no;no=Integer.parseInt(in.readLine();/System.out.print(no);String str=“ “;str=in.readLine().trim();/从服务器取得状态if(str.equals(“false“)JOptionPane.showMessageDialog(this,“对不起,出错了:- (“,“o