计算机网络,是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统。
而UDP 是User Datagram Protocol的简称, 中文名是用户数据报协议,是OSI(Open System Interconnection,开放式系统互联) 参考模型中一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务,IETF RFC 768是UDP的正式规范。UDP在IP报文的协议号是17。
UDP协议全称是用户数据报协议[1] ,在网络中它与TCP协议一样用于处理数据包,是一种无连接的协议。在OSI模型中,在第四层——传输层,处于IP协议的上一层。UDP有不提供数据包分组、组装和不能对数据包进行排序的缺点,也就是说,当报文发送之后,是无法得知其是否安全完整到达的。UDP用来支持那些需要在计算机之间传输数据的网络应用。包括网络视频会议系统在内的众多的客户/服务器模式的网络应用都需要使用UDP协议。UDP协议从问世至今已经被使用了很多年,虽然其最初的光彩已经被一些类似协议所掩盖,但是即使是在今天UDP仍然不失为一项非常实用和可行的网络传输层协议。
与所熟知的TCP(传输控制协议)协议一样,UDP协议直接位于IP(网际协议)协议的顶层。根据OSI(开放系统互连)参考模型,UDP和TCP都属于传输层协议。UDP协议的主要作用是将网络数据流量压缩成数据包的形式。一个典型的数据包就是一个二进制数据的传输单位。每一个数据包的前8个字节用来包含报头信息,剩余字节则用来包含具体的传输数据。
Java有非常好的网络支持,UDP由于其资源消耗少、容错性高,在视频会议、网络游戏的领域有很广泛的应用。
下面是一个基于UDP与Swing的一对一网络聊天系统,已经可以运行使用,其界面设计图如下:
下面是程序的源代码,亲测通过,其界面基本符合上述要求,但还有很多可以美化的地方,希望读者可以亲手设计改善一下!
运行效果:
源代码:
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;
/**
* 基于UDP与Swing的一对一网络聊天系统
* @author lijtaos
* @version 2.0
* @E-mail lijtaos@sina.com
*/
public class ChatI2U extends JFrame implements Runnable,ActionListener
{
/*----------------------------成员变量----------------------------
* @Param lblSendPort JLabel 发送端口标签
* @Param lblReceivePort JLabel 接收端口标签
* @Param lblPass JLabel 连接口令
* @Param lblIp JLabel 对方IP
* @Param textSendPort JTextField 发送端口文本行
* @Param textReceivePort JTextField 接收端口文本行
* @Param textSendMsg JTextArea 发送消息文本域
* @Param textSendMsg textShowMsg 接收消息文本域
* @Param btnListen JButton 监听消息按钮
* @Param btnSend JButton 发送消息按钮
* @Param thread Thread 线程对象
* */
/*-------------------GUI组件-----------------------*/
private JLabel lblSendPort,lblReceivePort,lblPass,lblIp;
private JTextField textSendPort,textReceivePort,textPass,textIp;
private JTextArea textSendMsg,textShowMsg;
private JButton btnListen,btnSend;
/*------------------------------------------*/
private DatagramPacket sendPacket,receivePacket;
private DatagramSocket sendSocket,receiveSocket;
private Thread thread=null;
private InetAddress sendIp,receiveIp;
private int sendPort,receivePort;
private byte[] inBuff,outBuff;
//----------------------------静态常量----------------------------
public static final int BUFF_SIZE=1024;
public static final int PASS=118899;
/*----------------------------成员方法----------------------------
* 构造方法 初始化交互界面
* */
/*构造方法
* 初始化交互界面
* */
public ChatI2U()
{
/*------------------------------------------------------*/
super();
getContentPane().setLayout(null);
setTitle("私聊一加一 Chat I2U"); //窗口标题
setBounds(100, 100, 500, 375); //窗口位置
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//关闭事件
/*1------------------------------------------------------*/
lblSendPort=new JLabel();
lblSendPort.setName("lblSendPort");
lblSendPort.setText("发送端口");
lblSendPort.setBounds(24, 29, 60, 15);
getContentPane().add(lblSendPort);
/*2------------------------------------------------------*/
lblReceivePort=new JLabel();
lblReceivePort.setName("lblReceivePort");
lblReceivePort.setText("接收端口");
lblReceivePort.setBounds(24, 62, 60, 15);
getContentPane().add(lblReceivePort);
/*1------------------------------------------------------*/
lblPass=new JLabel();
lblPass.setName("lblPass");
lblPass.setText("连接口令");
lblPass.setBounds(24, 95, 60, 15);
getContentPane().add(lblPass);
/*2------------------------------------------------------*/
lblIp=new JLabel();
lblIp.setName("lblReceivePort");
lblIp.setText("对方地址");
lblIp.setBounds(24, 128, 60, 15);
getContentPane().add(lblIp);
/*3------------------------------------------------------*/
textSendPort=new JTextField();
textSendPort.setName("textSendPort");
textSendPort.setBounds(90, 26, 90, 21);
getContentPane().add(textSendPort);
/*4------------------------------------------------------*/
textReceivePort=new JTextField();
textReceivePort.setName("textReceivePort");
textReceivePort.setBounds(90, 59, 90, 21);
getContentPane().add(textReceivePort);
/*3------------------------------------------------------*/
textPass=new JTextField();
textPass.setName("textPass");
textPass.setBounds(90, 92, 90, 21);
getContentPane().add(textPass);
/*4------------------------------------------------------*/
textIp=new JTextField();
textIp.setName("textIp");
textIp.setBounds(90, 125, 90, 21);
getContentPane().add(textIp);
/*5------------------------------------------------------*/
btnListen=new JButton();
btnListen.addActionListener(this);
btnListen.setName("btnListen");
btnListen.setText("开始监听");
btnListen.setBounds(24, 161, 156, 46);
getContentPane().add(btnListen);
/*------------------------------------------------------*/
textSendMsg=new JTextArea();
textSendMsg.setBorder(new LineBorder(Color.GREEN,1,false));
textSendMsg.setRows(5);
textSendMsg.setColumns(3);
textSendMsg.setName("textSendMsg");
textSendMsg.setBounds(24, 210, 156, 81);
getContentPane().add(textSendMsg);
/*------------------------------------------------------*/
btnSend=new JButton();
btnSend.addActionListener(this);
btnSend.setName("btnSend");
btnSend.setText("发送消息");
btnSend.setBounds(24, 293, 156, 46);
getContentPane().add(btnSend);
/*------------------------------------------------------*/
textShowMsg=new JTextArea();
textShowMsg.setRows(80);
textShowMsg.setColumns(40);
textShowMsg.setName("textShowMsg");
textShowMsg.setBorder(new LineBorder(Color.BLUE,2,false));
textShowMsg.setBounds(206, 10, 276, 321);
getContentPane().add(textShowMsg);
/*------------------------------------------------------*/
}
/*实现ActionListener接口的事件处理方法
*
* */
@Override
public void actionPerformed(ActionEvent e)
{
try
{
//按下监听按钮
if(e.getSource()==btnListen)
{
//未填入连接数据时
if(textSendPort.getText().trim()==null
||textIp.getText().trim()==null
||textReceivePort.getText().trim()==null
||textPass.getText()==null)
{
return;
}
//检查连接口令
if(Integer.parseInt(textPass.getText().trim())!=PASS)
{
textShowMsg.append("连接口令错误!");
return;
}
inBuff=new byte[BUFF_SIZE];
sendPort=Integer.parseInt(textSendPort.getText().trim());
receivePort=Integer.parseInt(textReceivePort.getText().trim());
sendSocket=new DatagramSocket();
receiveSocket=new DatagramSocket(receivePort);
receivePacket=new DatagramPacket(inBuff,BUFF_SIZE);
sendIp=InetAddress.getByName(textIp.getText().trim());
thread=new Thread(this);
thread.setPriority(thread.MIN_PRIORITY);
thread.start();
btnListen.setEnabled(false);
btnSend.setEnabled(true);
textSendMsg.setEditable(true);
}else{
outBuff=textSendMsg.getText().getBytes();
//打包要发送的数据
sendPacket=new DatagramPacket(outBuff,outBuff.length,sendIp,sendPort);
//发送数据
sendSocket.send(sendPacket);
textShowMsg.append("我说:"+"\n"+textSendMsg.getText()+"\n");
textSendMsg.setText(null);
}
}
catch (UnknownHostException uhe)
{
textShowMsg.append("无法连接到指定地址!");
}
catch(SocketException se)
{
textShowMsg.append("无法打开指定端口!");
}
catch (IOException ioe)
{
textShowMsg.append("发送数据失败!");
}
}
/*实现Runnable接口的线程执行体方法
* 在线程中执行服务
* */
@Override
public void run()
{
String msg=null;
while(true)
{
try
{
receiveSocket.receive(receivePacket);
msg=new String(receivePacket.getData(),0,receivePacket.getLength());
textShowMsg.append(sendIp.getHostAddress()+"说:\n"+msg+"\n");
}
catch (IOException e)
{
textShowMsg.append("接收数据失败!");
}
}
}
/*获取当前时间
* 在线程中执行服务
* */
/*----------------------------主方法----------------------------
*
* */
public static void main(String[] args)
{
ChatI2U chat=new ChatI2U();
chat.setVisible(true);
}
}