视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
网络课程设计实验报告--QQ聊天实现
2025-09-26 21:47:27 责编:小OO
文档
          计算机网络课程设计报告

                      

设计选题        网络聊天室

姓    名          马继鸣

            学    号          0909090630

          完成时间         2012-1-12

一、需求分析

聊天工具大多数由客户端程序和服务器程序外加服务器端,本程序采用客户机/服务器架构模式。通过Java提供的Socket类来连接客户机和服务器并使客户机和服务器之间相互通信,由于聊天是多点对多点的而Java提供的多线程功能。用多线程可完成多点对多点的聊天。

主要有两个应用程序,分别为服务器程序和客户端程序。服务器应用程序主要用于消息转发,以及向所有用户发送系统消息等;客户端应用程序主要用于客户聊天记录的显示和信息输入。采用Client/Server(C/S)体系结构,即客户机/服务器体系结构。聊天服务器专门用于监控用户状态和转发消息,客户端负责接收消息的用户序列和消息文本发送到服务器。该聊天系统实现群聊,用户登陆,退出聊天系统等功能。

二. 设计

1.设计思想:

   课程设计中利用JAVA实现基于C/S模式的聊天程序。聊天室共分为服务器端和客户端两部分,服务器端程序主要负责侦听客户发来的消息,客户端登录到服务器端才可以实现正常的聊天功能。

2.功能设计

   (1)服务器端的主要功能如下。

    在特定端口上进行侦听,等待客户端连接。用户可以配置服务端的侦听端口,默认端口为10000.

当停止服务时,断开所有用户连接。

   (2)客户端的主要功能如下。

    连接到已经开启聊天服务的服务端。

    当服务器端开启的话,用户可以随时登录与注销。

    用户可以向所有人发送消息。

3.详细设计

聊天室服务器端设计

聊天室服务器中主要的功能文件的功能如下:

MyButLis.java

主要用于添加事件侦听和动作处理,具体是服务器按钮中的“终止”“发送”的处理。

public class MyButLis implements ActionListener

 private MyServe server;

 private JTextField filed1;

 public void actionPerformed(ActionEvent e)

    

 MyChatSet.java

服务器的线程队列,运行的方法,新增一个用户,则增加一个线程,并可以返回应答消息,给其余用户发送上下线信息,发送聊天信息(群聊私聊虽然已写,但是不知为何没有实现),发送用户列表。关键在于除了线程之外,还定义了传输数据时的协议内容,如何分辨不同的信息,如聊天信息,登陆信息,上下线信息,并把信息完整准确的传递。

 

 public static ArrayList servers=new ArrayList();//线程队列

public static void addThread(MyserThread th) //增加一个服务器线程对象

public static void sendReMess(String type,String state,String s,MyserThread myth)//返回应答信息

 public static void SendOSMess(String type,String user)//其他用户上下线信息

public static void SendChatMess(String type,String sender,String reciver,String Mess)//聊天信息

 public static void SendList//用户列表

   

 MyCheckTool.java

保存用户的登陆信息,在其中建立一个码表,并且可以判断登陆信息是否合法。

//建立码表,用以保存用户信息

private static Map maps=new HashMap();

 public static boolean CheckUser(MyUserInfo user)// 验证用户名

MyFrame.java

建立服务器的主界面,关联侦听器。并启动线程。

MyFrame my=new MyFrame();

my.ShowUI();// 显示UI界面

public void ShowUI()

server.SetUP();

MyserThread.java

服务器线程类,定义输入输出流,发送读取信息,获取信息中相应标签的信息,用以判断用户名,密码,并可以中断连接。

this.socket=socket;

output=socket.getOutputStream();

input=socket.getInputStream();

public void SendMess(String s)//发送信息

public String ReadMess() //读取信息

public boolean ReadFirst()//将第一条信息读出来

public String GetValue(String type ,String Mess)

 public void Pocess()//用以判断用户名、密码

public void run()//线程开始 

public MyUserInfo getUser()//获得该线程中的用户信息

MyServe.java

建立服务器,并启动该线程。

server=new ServerSocket(inport);

Socket sc=server.accept();//获得socket对象

MyserThread th=new MyserThread(sc);

th.start();    //启动线程

客户端中主要的功能文件概述如下:

MyButLis.java

主要用于添加事件侦听和动作处理,具体是在客户端中的登陆注册发送等的处理。

public MyButLis(MySocketChat socket,JTextArea area1,JTextArea area2,MyLoginUI loginUI,JComboBox box)

public void actionPerformed(ActionEvent e) //设置动作

      

MyChatFrame.java

客户端的图形界面。关联侦听器。并启动线程。

socket.setArea(area1);

socket.start()

MyLoginUI.java 

登陆界面

MySocketChat.java

构建连接,截取字符串,发送登陆,注册,聊天信息,读取信息并判断设置启动线程方法。

 public MySocketChat(JTextField field1,JTextField field2,JTextArea area)//重写构造函数

public String GetValue(String type ,String Mess) //截取字符串

public void SendMess(String type)// 发送登陆或者注册信息

public void SendChat(String getter,String chat)// 发送聊天消息

public String ReadMess ()//读入的信息

public void CheckMess(String Mess) //判断是什么消息

public void run()//设置启动方法

三. 调试及测试

1、调试过程中遇到的主要问题及解决方法

    在对于群聊和私聊的处理中,只实现了群聊,私聊虽有写,但是还没有实现,由于时间仓促,只能在寒假的其余时间努力完成。

还有就是如何在服务器与客户端的信息交互过程中,让他们能分辨是哪种信息并准确的读出来。如果不能准确的分析,则数据的交换只能完成一种粗略的互换,而不能提取聊天内容等用户希望得到的信息。为此,我专门看了很多相关的资料,在很多方法里面选取了一种自己容易理解的方法,我就定义了几种方式,分别辨认登陆注册聊天列表等信息:

""+type+""+""+user+""+""+pwd+"";

//第一个与最后一个msg是标示一整句话的标示符  type标示数据类型,两个中间的type即为需求数据,两个之间的是用户名称,两个之间的pwd指的是密码

"chat"+""+user+""+""+getter+""+""+chat+"";

//其中sender,reciever,content分别指发送者、接受者、内容。

一些语法问题,在随着写程序的过程中,也慢慢纠正。在服务器组建中,由于java对于网络连接强有力的支持和丰富的代码,让我没有遇到太难的问题。

2、对设计和编码的回顾讨论和分析  

在获取系统时间这一块上,还是做得比较好。

Calendar ca=Calendar.getInstance();

Date da=new Date();// 注意是在java.util.Date

 SimpleDateFormat format=new SimpleDateFormat("HH:mm:ss");//设置时间格式

da=ca.getTime();

time=format.format(da);

    

处理保存的注册信息时,可能做得不是很好,将hashmap写入文件,这样不能长期保存注册信息,只能在服务器不关闭的状态下,保存注册信息。这个也会继续改进

3、程序运行的时空效率分析

本程序应用了线程对端口进行侦听。线程一直后台开启,长期占用系统资源,但又能及时的实现端口监听和消息的收发。

4、测试数据集

服务器端程序主界面:

可以记录用户名,账号,IP地址,并可以发送系统消息

客户登陆注册界面

注册成功提示框

客户端运行界面

用户端测试界面

中间的(全部)按钮, 点击后可以显示当前在线的好友列表,并选择聊天对象

四、经验和体会。

这是我第一次做java项目,只是这个学期选修了面向程序设计,每周一节课,很浅显的学习了java语言,在综合性如此强的项目设计中,感觉力不从心。

刚开始的一天里遇到了各种困难,不管是从原理上还是细节语法上,都感觉很难,索性前两天没有着手做, 只是在看别人的项目制作过程去学习思路,或者是在看java中的io stream,swing,awt,net的基础原理和内容,然后的才慢慢一步一步的开始做,因为慢,所以坚持写,一共五天的时间,有两天没有睡觉。还好有些设计基础,在最后终于可以完成一些基本的目标。通过这次程序设计,进一步巩固、加深了我们所学专业课程的基本理论知识,理论联系实际,进一步培养了综合分析问题,解决问题的能力,进一步加强了JAVA的实际应用能力。在网络知识中,也许这个知识点是可以铭记终身的。在如此痛苦又快乐的第一次的后面,我想,要我继续写别的程序的话, 我可以更有信息一些,一些流程已经了然于胸。不管怎么样,只有自己动手做了,才能是自己牢牢掌握的知识。所以我也会坚持去做些动手的内容,去锻炼自己。

关键段落的代码:服务器端

Myserve.java

package com.javake.Server;

import java.io.IOException;

import java.net.ServerSocket;

import java.net.Socket;

public class MyServe 

{

  private int inport; 

  private ServerSocket server;

  //重写构造函数    

  public MyServe(int inport)

  {

      this.inport=inport;

  }    

  //建立服务器    

    public void SetUP()

  {

      try {

            server=new ServerSocket(inport);

            while(true)

            {

                //获得socket对象

                Socket sc=server.accept();

                MyserThread th=new MyserThread(sc);

                //启动线程

                th.start();

            }

      } catch (IOException e) {

        // TODO Auto-generated catch block

        e.printStackTrace();

    }

  }

    public ServerSocket getServer() {

        return server;

    }

}

MyserThread.java

package com.javake.Server;

import java.io.*;

import java.net.Socket;

public class MyserThread extends Thread 

{

 private Socket socket;

  private MyUserInfo useIn; //用户对象

  private InputStream input;

  private OutputStream output;

  public MyserThread(Socket socket) //建立构造函数

  {

      this.socket=socket; //传入管道

      try {

         output=socket.getOutputStream();

         input=socket.getInputStream();

        } catch (IOException e) {

         // TODO Auto-generated catch block

         e.printStackTrace();

       }

  }

  public void SendMess(String s)

  {

      byte[] b=s.getBytes();

      try {

        output.write(b);

        output.flush();

    } catch (IOException e) {

        // TODO Auto-generated catch block

        e.printStackTrace();

    }

  }

  public String ReadMess()

  {

      StringBuffer buff=new StringBuffer();

      String s="";

      boolean end=false;

      int i=0;

      try {  //循环

         while(!end)

         {

              i = input.read();

              char c=(char)i;

              buff.append(c);

              s=buff.toString().trim();

         if(s.endsWith(""))

              {

                  s=new String(s.getBytes("ISO-8859-1"),"GBK").trim();

                  break;

              }

         }

        } catch (IOException e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

        }

      return s;

  }

  //将第一条信息出来

  public boolean ReadFirst()

  {

      String Mess=ReadMess();

      String flag=GetValue("type", Mess); //截取标记

      if(flag.equals("reg")) //判断是否为注册信息

      {

         String name=GetValue("name", Mess); //获得注册的用户

         String pwd=GetValue("pwd", Mess);

         MyUserInfo user=new MyUserInfo();

         user.setName(name);

         user.setPassWord(pwd);

       if( MyCheckTool.SetUser(user)) //验证注册是否成功

       {

             this.useIn=user;

             MyChatSet.sendReMess("regResp", "1", "欢迎来到进入聊天室", this);

             return true; } 

         else

               { MyChatSet.sendReMess("regResp", "0用户已存在,注册失败" , this);

             return false; }

      }

      if(flag.equals("login")) //判断是否为登陆用户

          { String name=GetValue("name", Mess); //获得注册的用户

         String pwd=GetValue("pwd", Mess);

         String IP=GetValue("IP", Mess);

         MyUserInfo user=new MyUserInfo();

         user.setName(name);

         user.setPassWord(pwd);

         user.setIPaddress(IP);

       if( MyCheckTool.CheckUser(user)) //验证登陆是否成功

            { this.useIn=user;

             MyChatSet.sendReMess("loginResp", "1", "欢迎来到进入聊天室", this); 

         MyChatSet.SendOSMess("onLine", this.useIn.getName());//发送用户上线消息

        MyChatSet.addThread(this); //将线程加入队列

        MyChatSet.SendList();//发送用户队列

             return true; } 

         else 

       {      MyChatSet.sendReMess("loginResp", "0用户名或账号错误" , this);  }

      }

      return false;

  }    //否则返回登陆失败

  public String GetValue(String type ,String Mess)

  {

int i=Mess.indexOf("<"+type+">")+type.length()+2;

int j=Mess.indexOf("");

      String s= Mess.substring(i,j);  //获得截取的信息

      return  s;

  }

  public void Pocess()//用以判断用户名、密码

  {

          if(ReadFirst())  //登陆或注册成功

      {

        String str=ReadMess();

        String tp=GetValue("type", str);

        while(tp!="offLine")

         if(tp.equals("chat")){//获得类型标签

         {

            String sender=GetValue("sender", str); //获得内容

            String getter=GetValue("reciver", str);

            String content=GetValue("content", str);

                MyChatSet.SendChatMess("chat", sender, getter, content); //发送消息}

         else if(tp.equals("offline")) //判断是否为下线消息

        {

            String user=GetValue("user", str);

            MyChatSet.SendOSMess("offline", user);

        }

         else if(tp.equals("login")) //注册后可能发来登陆消息

         {

               String name=GetValue("name", str); //获得注册的用户

               String pwd=GetValue("pwd", str);

               String IP=GetValue("IP", str);

               MyUserInfo user=new MyUserInfo();

               user.setName(name);

               user.setPassWord(pwd);

               user.setIPaddress(IP);

               if( MyCheckTool.CheckUser(user)) //验证登陆是否成功

                 {

                     this.useIn=user;

                     MyChatSet.sendReMess("loginResp", "1", "欢迎来到进入聊天室", this); 

                     MyChatSet.addThread(this);

                     System.out.println("二次注册或登录成功");

                      MyChatSet.SendList();

                      MyChatSet.SendOSMess("onLine", this.useIn.getName());//发送用户上线消息

                  }

                 else //将线程加入队列//发送用户队列

                 {

                     MyChatSet.sendReMess("loginResp", "0用户名或账号错误" , this);

                 }

         }

        str=ReadMess();

        tp=GetValue("type", str);

       }

     }

      try { //关闭socket

            socket.close();

        } catch (IOException e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

        }

  }

public void run()//线程开始 

 {

    Pocess();

 } 

  //获得该线程中的用户信息

  public MyUserInfo getUser() {

      return useIn;

  }

}

MyButLis.java

package com.javake.Server;

import java.awt.event.*;

import java.io.IOException;

import javax.swing.JTextField;

public class MyButLis implements ActionListener{

    private MyServe server;

    private JTextField filed1;

    public MyButLis(MyServe server,JTextField filed1)

    {

        this.server=server;

        this.filed1=filed1;

    }

    @Override

    public void actionPerformed(ActionEvent e) {

        String s=e.getActionCommand();

        System.out.println("服务器在运行");

        if(s.equals("终止"))

        {

          System.out.println("在进行中");

          try {

            server.getServer().close();                

          } catch (IOException e1) {

            // TODO Auto-generated catch block

            e1.printStackTrace();

        }

        }

        else if(s.equals("发送"))

        {

            MyUserInfo user=new MyUserInfo();

            user.setName("服务器");

            String Mess=filed1.getText();

            MyChatSet.SendChatMess("chat", user.getName(), "", Mess);

            filed1.setText("");

        }

    }

}

MyChatSet.java

package com.javake.Server;

import java.util.ArrayList;

import javax.swing.SwingUtilities;

import com.javake.Server.MyFrame;

public class MyChatSet 

{ public static ArrayList servers=new ArrayList();//线程队列

  public static void addThread(MyserThread th)  //增加一个服务器线程对象

  {

      servers.add(th);

      SwingUtilities.updateComponentTreeUI(MyFrame.table);

      System.out.println("有"+servers.size()+"在线上");

  }

  public static void sendReMess(String type,String state,String s,MyserThread myth)

  {

myth.SendMess(""+type+""+""+state+""+""+s+""+"");

  }       

  public static void SendOSMess(String type,String user)

  {

for(int i=0;i           {

             

             MyserThread myth=servers.get(i); //获得线程类

         myth.SendMess(""+type+""+""+user+""+"");

           }  

  }

   public static void SendChatMess(String type,String sender,String reciver,String Mess)

   {

       if(reciver.equals(""))//如果获得的接受者为“”就是群发

       {

         for(int i=0;i              {

                 MyserThread myth=servers.get(i);      //获得线程类

             myth.SendMess(""+type+""+""+sender+""+""+reciver+""+""+Mess+""+"");

              }       

        }

       else //发送给某个对象

       {

     for(int i=0;i              {

                 //获得线程类

                 MyserThread myth=servers.get(i);

                if(myth.getUser().getName().equals(reciver))

                 {

                 myth.SendMess(""+type+""+""+sender+""+""+reciver+""+""+Mess+""+"");

                 }

              }       

       }

   }

  public static void SendList()

  {

String list="budyList全部,";

for(int i=0;i      {

          MyserThread ser=servers.get(i);

          String name=ser.getUser().getName();

          list=list+name+

      }

list=list+"";

for(int i=0;i      {

          MyserThread ser=servers.get(i);

          ser.SendMess(list);      //给每个在线用户发送列表

      }

  }

}

客户端:

MySocketChat.java

package com.javake.MySocket;

import java.io.*;

……..

{

  private Socket socket;

  private String IP="localhost"; 

  private InputStream input;

  private OutputStream output;

  private JTextField field1;

  private JTextField field2;

  private String user;

  private JTextArea area;

  private boolean end=false;

  private MyChatFrame my;

  public MySocketChat(JTextField field1,JTextField field2,JTextArea area)

  {

    this.field1=field1;

    this.field2=field2;

    this.area=area;

    //建立socket

    try {

        socket=new Socket(IP,10000);

        input=socket.getInputStream();

        output=socket.getOutputStream();

    } catch (UnknownHostException e) {

        e.printStackTrace();

    } catch (IOException e) {

        e.printStackTrace();

    }

  }

  public String GetValue(String type ,String Mess)  //截取字符串

  {

int i=Mess.indexOf("<"+type+">")+type.length()+2;

int j=Mess.indexOf("");

      String s= Mess.substring(i,j);  //获得截取的信息

      return  s;

  }

  public void SendMess(String type)

  {

      user=field1.getText();//账号

      String pwd=field2.getText();//密码

      String Mess="";

      if(type.equals("reg"))

     {

     Mess=""+type+""+""+user+""+""+pwd+"";

     }else

     {

Mess=""+type+""+""+user+""+""+pwd+""+socket.getRemoteSocketAddress().toString().trim()+"";

     }

      byte[] b=Mess.getBytes();//获得字符

      try {

        output.write(b); //输出

        output.flush();

      } catch (IOException e) {

        // TODO Auto-generated catch block

        e.printStackTrace();}

  } 

  public void SendChat(String getter,String chat)

      { String

str="chat"+""+user+""+""+getter+""+""+chat+"";

    byte[] b=str.getBytes();

    try { output.write(b);

        output.flush();

    } catch (IOException e) {

        // TODO Auto-generated catch block

        e.printStackTrace();}

  }

      public String ReadMess  () throws IOException 

        {  StringBuffer buff=new StringBuffer();

          String s="";

          int i=0;

          boolean flag=false;

           while(!flag) //循环

            {      i = input.read();

                  char c=(char)i;

                  buff.append(c);

                  s=buff.toString().trim();

             if(s.endsWith(""))

                  {

                      s=new String(s.getBytes("ISO-8859-1"),"GBK").trim();

                      break;

                  }

            }

          return s;

      }

public void CheckMess(String Mess) //判断是什么消息

{

    String time;

    Calendar ca=Calendar.getInstance(); 

    SimpleDateFormat format=new SimpleDateFormat("HH:mm:ss");

    java.util.Date da=new java.util.Date(); 

    String type=this.GetValue("type", Mess);

    da=ca.getTime();

    time=format.format(da);

    if(type.equals("chat"))

    {//当读入的类型是chat

        String sender=this.GetValue("sender", Mess);

        String content=this.GetValue("content", Mess);     

         area.append(time+"\\r\\n"+sender+"说: "+content+"\\r\\n");

    }

    else if(type.equals("offLine")) //上下线信息

    {

        String name=this.GetValue("user", Mess);    

        String show=name+"  下线了";

        area.append(time+"\\r\\n"+show+"\\r\\n");

        end=true;

     }

    else if(type.equals("onLine"))

    {

        String user=GetValue("user", Mess);    

        area.append(time+"\\r\\n"+user+"上线了\\r\\n");

    }

    else if(type.equals("budyList"))

    {

System.out.println("------->用户列表已收到");

      String users=this.GetValue("users", Mess);

      StringTokenizer toke=new StringTokenizer(users,

      JComboBox box=MyChatFrame.box;

      box.removeAllItems();

      while(toke.hasMoreElements())

       {

         String Item=toke.nextToken();

         box.addItem(Item);

       }

System.out.println("------->box列表"+box.getItemCount());

    }

    

public Socket getSocket() {

    return socket;

}

public void setSocket(Socket socket) {

    this.socket = socket;

}

public void run()//设置启动方法

{

   try{

        String Mess=this.ReadMess();

       while(!end)

       {

         this.CheckMess(Mess);

         Mess=this.ReadMess();

       }

   }

      catch(Exception e)

     {

        e.printStackTrace();

     }

}

public JTextArea getArea() {

    return area;

}

public void setArea(JTextArea area) {

    this.area = area;

}

public MyChatFrame getMy() {

    return my;

}

public void setMy(MyChatFrame my) {

    this.my = my;

}}下载本文

显示全文
专题