Java聊天程序(基于UDP)

什么是UDP?
UDP是一种网络通讯协议,叫做数据报包协议。
UDP协议具有以下特点:
1、计算机与计算机之间不需要建立连接,速度较快。
2、通过数据包的方式发送数据,数据包一般不超过64KB,适合传输较小的数据。
3、数据包包括要发送到数据,如文本数据等等,以及发送端主机和目标主机的IP和端口信息。
4、通过数据包中的目标主机的信息寻找目标主机,如果目标主机不存在或者没有连接到互联网中,数据包会丢失,可靠性低。
打个小比方:UDP通信就好比寄快递·(这里为了形象,不考虑速度问题),寄快递的人(发送端主机)只需要把要发送的东西打包好,填上要快递过去的地址(目标主机的地址信息),快递就会寄出去。如果目标地址比如说是火星,快递员送不过去,因为火星不在地球范围内(火星就是目标主机,但它没有在地球上,即目标主机没有连接到互联网上),那快递员一看是火星,这不是逗他玩吗,他一生气就把包裹丢了。

    本人虽然只是一个大一的学生,这个学期刚刚学完Java,但是本人对Java有着极大的学习兴趣和热情,各种寻找资源提升自己的实力。这不,刚刚看完毕向东老师的网络编程教学视频,自己动脑想了这个项目,并动手实现了这个项目,还是感到挺开心的。

    现在,我来展示一个我自己写的一个基于UDP协议的Java聊天程序。(各位放心,我注释写的非常详细,但愿不要嫌我啰嗦就好吐舌头

import java.io.IOException;
import java.net.*;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JTextArea;
/**
 *
 * @author flying duck
 */
/**
 * 1、自定义一个线程,用来接收来自对方的消息。
 * 2、关于为什么要单独开启一个线程来接收对方的消息?
 *    那是因为,对方发消息是不定时的,而且发消息的个数不确定,顺序也不确定。
 *所以如果在主线程里接收消息,并不能“同时执行(肉眼看起来是如此)”发消息和
 *接收消息。
 * 3、该线程也不需要同步,因为主线程和该线程不共享数据,不会造成共享数据的不安全性。
 */
public class Receiver implements Runnable{  //实现Runnable接口,使其变成一个线程任务类。
    
    DatagramSocket ds;      //UDPSocket对象。
    
    JTextArea jt;       //文本区域。
    
    DatagramPacket dp;      //数据报包对象。
    
    byte[] by=new byte[1024];   //用来接收数据的字节数组。
    
    public Receiver(JTextArea jt) throws SocketException{   //因为要将收到的消息显示在文本区中,所以将文本区传进来。
        
        this.jt=jt;
        
        ds=new DatagramSocket(20000);   //自己的接收端端口,必须指定(因为对方要发送数据到己方,必须知道己方的端口)。
        
        dp=new DatagramPacket(by,by.length);    //实例化接收数据报包,包括用来存放接收到的数据的字节数组以及要接收的放在字节数组中长度。
        
    }
    public void run(){      //Runnable接口中的方法(必须实现),线程开启后执行的代码。
        
        while(true){        //因为要不断地接收消息,所以线程要一直运行,所以用while(true)。
            
            try {
                ds.receive(dp); //接收消息,当没有接收到消息时,此方法处于阻塞状态。会一直在此等待,直到接收到数据为止。
                
                jt.append("对方说:"+new String(dp.getData(),0,dp.getLength())+"\n");   //将对方发来的消息显示在文本区域。
                
            } catch (IOException ex) {
                Logger.getLogger(Receiver.class.getName()).log(Level.SEVERE, null, ex); //一种异常处理,不必深究。
            } 
        }
    }

}



    import java.awt.*;
import java.awt.event.*;
import java.io.IOException;
import javax.swing.*;
import java.net.*;
import java.util.logging.Level;
import java.util.logging.Logger;


/**
 *
 * @author flying duck
 */
/**
 * 基于UDP协议的两个程序进行聊天思路:
 * 1、创建UDP的Socket对象。
 * 2、创建数据发送包和数据接收包对象,UDP是以收发数据包进行通信的。
 * 3、画一个GUI界面,有文本框,按钮和一个文本区域。
 * 4、当点击发送按钮时发送数据至接收端。
 * 5、接收部分设置一个线程,用来接收数据。
 */
public class TalkFrame extends JFrame implements ActionListener{   //继承JFame并实现动作侦听器接口,使该类成为窗体类和侦听器。
   
    DatagramSocket ds;  //UDP通信的Socket对象,在java.net包里。
    
    DatagramPacket dp;  //数据报包对像。
    
    JTextArea jt;   //文本区域用来显示消息。
    
    JTextField jf;  //文本框,用来写要发送的消息。
    
    JButton jb;     //按钮,点击按钮,发送消息。
    
    JScrollPane jsp;    //滚动面板,用来放置文本区域的,不是必须的。
    
    Receiver rec;   //自定义的线程任务对象,用来接收来自对方的消息。
    
    Thread th;      //线程对象,用来由线程任务创建线程对象。
    
    byte[] by=new byte[1024];   //字节数组,用来将要发送的字符串转变成字节数组,因为数据报包智能发送单个字节或字节数组。
    
    public TalkFrame() throws SocketException{ //构造方法,对聊天框进行对象的初始化以及一些设置。
        
        super("聊天框");    //调用超类JFrame的构造方法设置聊天框的标题。
        
        ds=new DatagramSocket();    //初始化UDPSocket对象,如果不指定端口,则默认选取任意一个可用端口。
        
        jt=new JTextArea(20,20);    //初始化文本区域并设置其为20行和20列(一个字符代表一列)。
        
        jf=new JTextField(20);      //初始化文本框,设置其容量为20个字符。
        
        jb=new JButton("发送");     //初始化按钮。
        
        jsp=new JScrollPane(jt);    //初始化滚动面板,并把文本区域放置在滚动面板中。
        
        this.setLayout(new FlowLayout());   //设置窗体布局为流式布局(此布局为从左向右一次添加组件,一行放不下了转到第二行)。
        
        this.add(jf);   //将文本框加到窗体中。
        
        this.add(jb);   //将按钮加到窗体中。
        
        this.add(jsp);  //把滚动面板加到窗体中。
        
        jb.addActionListener(this);     //为按钮注册动作事件侦听器(当点击按钮时触发动作事件),因为该类实现了动作事件侦听器接口,所以该类对象就是侦听器。
        
        jf.addActionListener(this);     //为文本框注册动作事件侦听器,当按下回车触发动作事件。
        
        this.setVisible(true);      //设置窗体可见(窗体默认是不可见的)。
        
        this.setBounds(400,200,500,400);        //设置窗体边界和大小。
        
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);    //设置窗体默认关闭操作。
        
        rec=new Receiver(jt);   //实例化自定义线程任务对象。
        
        th=new Thread(rec);     //用线程任务对象创建一个线程。
        
        th.start();     //开启该线程,使其接收来自对方的消息。
        
    }
    public void actionPerformed(ActionEvent e){     //ActionListener接口里的方法,必须实现,用来处理当点击按钮或者在文本框按下回车后的动作事件。
        if(jf.getText().length()>0){        //当文本框里面字符串长度大于零时(如果长度为0,则没有意义)执行下面语句。
            try {
                String message=jf.getText();    //把文本框中的文本提取出来。
                by=message.getBytes();  //将字符串转变为字节数组。
                dp=new DatagramPacket(by,by.length,InetAddress.getByName("10.200.17.135"),20005);   //实例化数据报包,包括要发送的字节数组以及长度,对方的InetAddress对象和端口号。
                try {
                    ds.send(dp);    //发送数据报包。
                    jt.append("你说:"+message+"\n");   //将你发送的消息显示在文本区中。
                    jf.setText("");     //发送完消息后,清空文本框(以便下次输入)。
                } catch (IOException ex) {
                    Logger.getLogger(TalkFrame.class.getName()).log(Level.SEVERE, null, ex);//一种异常处理,不必深究。
                }              
            } catch (UnknownHostException ex) {
                Logger.getLogger(TalkFrame.class.getName()).log(Level.SEVERE, null, ex);//一种异常处理,不必深究。
            }
       }
    } 

}



import java.net.SocketException;


/**
 *
 * @author flying duck
 */
public class Talker1 {


    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws SocketException {
        // TODO code application logic here
        TalkFrame tal=new TalkFrame();  //那就弄呗。
    }
    
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值