Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 346|回复: 0

[Java基础知识]jICQ 服务器和客户端源码

[复制链接]
  • TA的每日心情
    开心
    2021-3-12 23:18
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2014-10-1 23:08:35 | 显示全部楼层 |阅读模式
    jICQ系统是作者自2001年4月份开始开发的一个小型软件,最初旨在提高作者自己的java应用水平,在经过一段时间完善之后,便不由自主的想使这个小小的应用更加完美,所以现在仍在不断的升级,希望有更多的java爱好者能加入这个开发行列中来,也希望熟悉java的人能更多关心java应用的发展,愿更多的java爱好者参与一起完善这个程序. 一.概述
    二.系统原理
    三.中文处理

    一.概述:
    系统是基于ICQ和OICQ系统的基本特性编制面出.
    系统在事件处理上采用java2的组件监听机制.
    系统图形用户界面全面采用AWT组件,未采用SWING,因为SWING的JRE太大.软件兼容jdk1.1.8及以上,兼容win98SE自带ms java平台.  
      
      

    界面全部使用手工编制.
          由于jdk1.1.8不支持图象Label,所以jICQ主画面全部由paint(){}方法完成,面事件由窗体的自定义鼠标事件驱动.

    使用java.awt.image.*;图像技术,加亮图片,使郊果别据一色,并且解决了,MS的java平台图像处理系统的缺点(即图象常常只显示一部分,另外部分显示不出,用repaint()方法重绘也不能解决).

    客户端与服务端采用TCP/IP连接,传输稳定,客户端与客户端采用UDP传输,并施行UDP控制,能发现丢包,并能提交服务器转发,能发现UDP重复包并实现控制.

    实现广告链接(体现java网络特性).
    系统参数可保存.
    实现中文传输.
    服务器采用java Application.
    与服务器的所有通信都由Class Sender完成,Sender做完一件事后返回一个Result对象(包括一个返回码(int)及一条返回信息(String)).  类列表:
    public class jICQ //系统主类含main()方法
    class MainFrame extends Frame implements Runnable //被jICQ.main() 初始化并启动
    class RMsg extends Thread //被MainFrame.run()初始化并启动
    class SMsg extends Frame //被MainFrame.run()初始化
    class LogonFrame extends Frame //被MainFrame.run()初始化
    class Result //服务于Sender
    class IcqID extends Thread //公用类,为每个好友产生一个实例,当IcqID.newMsg==true时自启动,能处理收到和发送信息.
    class Sender extends Thread //公用类,专门与服务器进行通信,接受String型命令,以线程序方式运行,执行结束返回一个Result对象
    class SubmitID extends Frame //可用来注册,修改和查看用户信息.
    class Seek extends Frame //负责查找好友.被MainFrame的右键菜单调用.
    class MyDialog extends Frame //产生一个对话框
    class SysInfo extends Frame //为MainFrame提供用户设置变量,读取和保存jICQ.ini文件.
    class HttpImage extends Thread //在MainFrame被构造时调用并启动,负责为SMsg提供广告图片getImg()和超级链接getHttp()



    二.系统原理
    1.主要类及主要方法,重要变量:
         系统启动后调用 jICQ 中的main()方法,出更登录框,系统后台查找主机地址(服务器有多个可能域名).等待正确登录,如果号码密码验证通过,则初始化jICQ主界面,并启动主界面的后台线程.jICQ.class的使命完成,接后的工作由MainFrame完成.

    MainFrame 即为主界面,继承Frame并实现线程,初始化时为整个系统初始化变量,并把所有头像图片装入headImg[]中,并处理头像图片数据变白后放入alphaHead[]数组中.

    ----其run()方法完成登录服务器的全过程,并启动多个其它线程([1]Sender.onlineMon()方法主要是TCP/IP连接服务器一直到程序结束,[2]RMsg.class类主要是监听UDP端口,接收来自其它用户的聊天内容),当登录完成后,成为调度线程直到结束,执行比如有聊天信息收到使主窗口图标闪烁(调用checkID()),自动更新好友的个人信息checkID(),如果出果重绘窗口请求(repaintEvt==true),则调用repaint()重绘屏幕;监视Sender.onlineMon()是否与服务器断线,是则重连;监视服务器是否发来他人用自已这个号码在登录(duplogon==true),是则出现提示对话框,结束系统.

    ----其paint()方法,完成主界面的图形绘制工作.它把主窗口分为七块, 为每块区域分配不同的作用:(1)上翻页;(2)头像区(调用IcqID.draw()方法);(3)下翻页;(4)添加好友;(5)消息通知;(6)修改菜单;(7)LOGO图标,并有大小图标转换功能.
    ----process...系统方法为事件处理方法.

    ----Hashtable Friend是用来存放好友名单的表,其键为jicq号码(String icqNo), 其值为个人资料的对象(IcqID icqid);存入方法为:setFriend(String key,Object value)

    RMsg 继承线程,在主窗口存在时,终生存在.为接收UDP包的类,从接收到的包里区分出发送者,检索好友中是否有此人,如果无,则添加为陌生人.
    SMsg 是一个Frame.主要接收用户的输入,把输入结果传输给IcqID的addInMsg()方法.

    LogonFrame 这是一个启动登录对话框的窗体(可设置代理服务器),可以完成两个工作,(1)实现登录,当用户输入jICQ号码及密码后点击登录按钮,即调用启动一个Sender线程,当Sender返回代码为Result.getCode()=200时说明登录成功,此时LogonFrame调用jICQ.class的setID()方法把登录的jICQ号传给jICQ.class(以便接下来MainFrame(jICQ.icqNo)用.)登录结束.(2)即当点击注册按钮时,new 一个SubmitID的实例.

    Sender 继承线程,被调用方法为(它接受的命令以字符串为参数,根据字符串的内容确定执行什么操作,类似于WEB服务器):

    Sender sender=new Sender("LOGON icqNo:"+s1+" password:"+s2);
    sender.start();
    Result result=sender.getReturn(); //或 Result result=sender.getReturn(int timeOut);
    if(result.getCode()==200){
           jICQ.setID(s1);dispose();
    } else{
          tf_msg.setText(result.getMsg());
    }

    此Sender在执行结束时返回一个Result对象.
    IcqID 为每个好友创建一个实例,所有的实例都被放在Hashtable MainFrame.Friend;中.每个实例包括好友的个人信息及运行状态,并有一些辅助功能,比如:(1)IcqID.draw()被MainFrame.paint()方法调用绘出自已在MainFrame窗体中的头像,(2)能够处理收到addInMsg()的信息和用发出addOutMsg()信息,先用UDP发送udpSend(),确定UDP包是否到达(run()中完成),如果在超时设置内没有接收到回应,即认为是未到达,采用服务器转发.(3)IcqID.getImg()为其它类提供自已的头像.(4)自动实现新信息到达时头像闪动(在run()方法中实现).(5)mouseEnter()和mouseExit()被MainFrame.proceSSMouseMotionEvent()调用,实现鼠标移动时头像变白的效果.

    SubmitID 主要是好友的个人信息显示提供一个界面,同时兼具注册及修改个人资料的用途.
    Seek 主要完成好友的查找及添加工作,当添加时向MainFrame.friend哈希表中添加一个IcqID实例就可以了.  2.运行状态:
    整个个程序在运行期间有四个线程终生存在:
    MainFrame.run() //系统调度
    RMsg.run() //UDP监听,并分析UDP包,确定来自哪位好友,并调用Friend中的该好友的IcqID.addInMsg()添加信息.
    Sender.run() //调用onlineMon()主动与服务器连接后保持连接并接收来自服务器的信息:

    (1)转发的好友信息,
    (2)别人要添加自己为好友,
    (3)系统消息,
    (4)好友上线下线.
    SysInfo.run() //当SMsg运行时,每间隔8秒钟为SMsg.ImagePanel提供广告图片和URL.
    系统中IcqID也有run()方法,但是它的实例线程不是一直在运行,当有信息发出或收到时才会触发,当读了信息后,线程就结束了.  3.特定事件的处理流程:
    (1)登录:
    jICQ.main()-->LogonFrame.login()验证如果通过(jICQ此时处理哪个jICQ服务器正开通着)-->修改jICQ.icqNo-->jICQ初始化MainFrame-->启动MainFrame线程-->jICQ结束,控制权转到MainFrame.run()
    MainFrame.run()启动-->确定此机器的UDP接收端口(因此可实现多个jICQ同一台机运行)-->启动Sender.onlineMon()线程监听来自服务器的信息-->让Sender执行"GETME"命令,同时提交自已的UDP端口号,取得自己的个人资料,把好友名单用toHash()放入Friend中.把在线名单用toID()修改(IcqID)Friend.getFriend(icqNo).isOnline=true-->登录结束,run()开始无限循环,直到系统结束.

    (2)收到UDP信息:
    当收到UDP信息时udpRSocket.receive(dp)
    -->如果是好友聊天信息("MSG")-->分析发送方的号码-->从MainFrame.Friend中查找是否是好友,不是则加为陌生人-->取得Friend表中的此人的IcqID,调用IcqID.addInMsg()-->在addInMsg()中-->首先判别是否是第二次收到重复信息(实际应用中可能收到两次同一条消息),如果重复则不做任何处理.-->是新消息-->设IcqID.newMsg=true,给MainFrame.repaintEvt=true,即让主窗口重绘.-->向发送者回复一条"UDPOK"的消息-->如果用户允许自动回复(MainFrame.sysinfo.autoRe==true),刚发送自动回复内容(MainFrame.sysinfo.autoReText)--完成.
    -->如果是确认信息("UDPOK")-->取出MainFrame.friend表中发送方的IcqID-->调用IcqID.backID()-->去掉Vector IcqID.outMsg中的已发出内容这条数据(否则IcqID.run()中在检测到某条信息在超时后仍未收到确认信息,则会自动通过服务器转发)

    (3)发送一条聊天信息:
    MainFrame.processMouseEvent()或MainFrame.processKeyEvent()接收到一条发信息的指令后,构造一个SMsg()窗口,等待用户输入聊天内容-->接到发送指令-->调用好友的IcqID.sendOut()方法-->在IcqID.sendOut()中-->构造一条发送命令,并截去太长的字符串,为这个信息加上一条ID(以便接收方面军区别是否重复收到同一信息)-->调用addOutMsg(),向Vector IcqID.outMsg添加发出的消息,以便run()方法检查确定是否重发-->启动自已的run()方法-->结束  4.图形用户界面:
    最先的jICQ是使用的jdk1.0的事件处理方法handleEvent(),后来从jICQ1.2开始便改为事件监听机制,从而使设计更易懂.
    除MainFrame之外,其它的窗体都使用java.awt.*;中的组件,使用java.awt.bagGridLayer布局管理器,手工设计,便于修改.
    MainFrame窗体中未使用任何组件,因为在处理大量的好友时,组件就觉得无所适从,所以全部用Graphics.draw...()方法产生,当然在不用组件时,也产生了大量的问题, 比如说, 在中文Linux系统中,就出现组件中的中文显示正常,面drawString()绘出的中文就显示为方格,很不方便.而绘出的图形再分为几个区,由processMouseEvent()处理鼠标事件.

    二.中文处理
    在传输入过程中,使用早期的DataInputStream.readLine()和PrintStream.println()方法,不能传输中文,但传输英文数字没问题.但是采用手工转换Char为Byte[]时,就可以解决这个问题.用下面的两个方法可以实现中文传输,但收发双方要相应使用这两个方法.
    void sendString(PrintStream ps,String s) {
        ps.println(s.length());
        int len=s.length()*2;
        byte buf[]=new byte[len];
        try{
          for(int i=0;i<s.length();i++){buf[i*2]=(byte)(s.charAt(i)>>8);buf[i*2+1]=(byte)s.charAt(i);}
          ps.write(buf,0,len);
          ps.flush();
          bos.flush();
        } catch(Exception e){System.out.println(" sendString() error:"+e);}
          //System.out.println(" has sent.");
        }

    String receivString(DataInputStream in) {
        String inline="";
        int len=0;
        try{
        inline=in.readLine();
        for(int i=0;inline.equals("");i++){inline=in.readLine();Thread.sleep(100);if(i==300)return "";}
        len=new Integer(inline).intValue();
       }catch(Exception e){System.out.println(" receivString() error:"+e);}
       char c[]=new char[len];
       byte buf[]=new byte[len*2];
       try{in.readFully(buf);}
       catch(IOException e){System.out.println(" receivString() error:"+e);}
       for(int i=0;i<len;i++)
       {c=(char)(buf[i*2]<<8);c=(char)((c&0xff00)|(0x00ff&buf[i*2+1]));}
       String s=null;
       s=new String(c);
       return s;
    }

      
      
       
       

         
       

         
       
      
      

    源码下载:http://file.javaxxz.com/2014/10/1/230833031.zip
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-5-18 19:26 , Processed in 0.391786 second(s), 48 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表