本实例使用UDP设计一个小聊天程序
首先我们应当知道,UDP协议是一种不可靠的传输协议,不想TCP协议建立了可靠的链接
即UDP只管发送不管是送送达,但是我们设计的聊天程序是需要可靠的传输的,所以我们需要拓展UDP的使用
添加两个技术:
1.添加检验功能,保证数据传输的正确性;
2.添加可靠的传输技术,保证数据能传送达到;
程序的界面设计如下:
简单而达到了基本功能的使用
1.添加的校验功能主要是在java 的CRC的基础上进行实现的,利用了JAVA 的自动CRC实现
2.程序的可靠传送我们利用了TCP的思维,在不是建立一个链接,但是我们使其接收端发送一个回执的信息,告诉发送端接受成功,即使没有回执信息,设计发送端在没有接受的回执信息的时候,重复三次发送,在三次发送都没有回执信息的情况下,我们即可认为接收端不可达
程序的源代码:
import java.io.*;
import java.net.*;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.event.*;
import javax.swing.*;
public class UDPChat implements Runnable, ActionListener{
JTextArea showArea;
JLabel lb11, lb12, lb13;
JTextField msgText, sendPortText, receivePortText, IPAddressText;
JFrame mainJframe;
JButton sendBtn,startBtn;
JScrollPane JSPane;
JPanel pane1, pane2;
Container con;
Thread thread=null;
DatagramPacket sendPack, receivePack;
DatagramSocket sendSocket, receiveSocket;
private InetAddress sendIP;
private int sendPort, receivePort;//储存发送端口和接收端口
private byte inBuf[], outBuf[];
public static final int BUFSIZE=1024;//最大传输包大小
private static final int TIMEOUT = 5000; //设置接收数据的超时时间
private static final int MAXNUM = 3; //设置重发数据的最多次数
public UDPChat ()
{
mainJframe=new JFrame("短信——udp协议");
con=mainJframe.getContentPane();
showArea=new JTextArea();
showArea.setEditable(false);
showArea.setLineWrap(true);
lb11=new JLabel("接收端口号");
lb12=new JLabel("发送端口号");
lb13=new JLabel("对方IP地址");
sendPortText=new JTextField();
sendPortText.setColumns(5);
receivePortText=new JTextField();
receivePortText.setColumns(5);
String ip= GetIP();
IPAddressText=new JTextField(ip);
IPAddressText.setColumns(8);
startBtn=new JButton("开始");
startBtn.addActionListener(this);
pane1=new JPanel();
pane1.setLayout(new FlowLayout());
pane1.add(lb11);
pane1.add(receivePortText);
pane1.add(lb12);
pane1.add(sendPortText);
pane1.add(IPAddressText);
pane1.add(startBtn);
JSPane=new JScrollPane(showArea);
msgText=new JTextField();
msgText.setColumns(40);
msgText.setEditable(false);
msgText.addActionListener(this);
sendBtn=new JButton("发送");
sendBtn.setEnabled(false);
sendBtn.addActionListener(this);
pane2=new JPanel();
pane2.setLayout(new FlowLayout());
pane2.add(msgText);
pane2.add(sendBtn);
con.add(pane1,BorderLayout.NORTH);
con.add(JSPane,BorderLayout.CENTER);
con.add(pane2,BorderLayout.SOUTH);
mainJframe.setSize(600,400);
mainJframe.setVisible(true);
mainJframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainJframe.setLocationRelativeTo(null);
//构建聊天窗口
}
public static void main(String[] args)
{
new UDPChat( );
}
public void actionPerformed(ActionEvent e){
try{
if(e.getSource( )==startBtn){//按下了开始按钮
inBuf=new byte[BUFSIZE];
sendPort=Integer.parseInt(sendPortText.getText());
sendIP=InetAddress.getByName(IPAddressText.getText());
sendSocket=new DatagramSocket();
receivePort=Integer.parseInt(receivePortText.getText());
//创建接收数据包
receivePack=new DatagramPacket(inBuf,BUFSIZE);
//指定接收数据端口
receiveSocket=new DatagramSocket(receivePort);
//创建线程准备接收对方消息
thread=new Thread(this);
thread.setPriority(Thread.MIN_PRIORITY);
thread.start();
startBtn.setEnabled(false);
sendBtn.setEnabled(true);
msgText.setEditable(true);
}
else{
//新建监视线程发送数据
new Thread()
{
public void run()
{
String dataString=CheckCRC.AddCRCToken(msgText.getText());
outBuf=dataString.getBytes();
//组装要发送的数据包
sendPack=new DatagramPacket(outBuf,outBuf.length,sendIP,sendPort);
byte[] buf = new byte[1024];
DatagramPacket dp_receive = new DatagramPacket(buf, 1024);
try
{
DatagramSocket sendSocketNew=new DatagramSocket();
sendSocketNew.setSoTimeout(TIMEOUT); //设置发送数据后超时重传的等待时间
int tries = 0; //尝试重发数据的次数
boolean receivedResponse = false; //是否接收到消息回执的信号量
String msgData=msgText.getText();
showArea.append("我说:"+msgData+"\n");
msgText.setText(null);
while(!receivedResponse && tries
检验功能源代码:
import java.util.zip.CRC32;
public class CheckCRC
{
/**
* 计算出CRC校验码
* @param data
* 数据
* @return
* CRC校验码
*/
private static String GetCRC(String data)
{
CRC32 crc =new CRC32();
crc.update(data.getBytes());
String returnString= Long.toHexString(crc.getValue());
while (returnString.length()<8) returnString="0"+returnString;
while (returnString.length()>8) returnString=returnString.substring(0, 7);
return returnString;
}
/**
* 从Data+CRC中提取CRC
* @param Token
* (即Data+CRC组合)
* @return
* CRC
*/
private static String GetCRCFromToken(String Token)
{
int length=Token.length();
return Token.substring(length-8, length);
}
/**
* 从Data+CRC中提取Data
* @param Token
* (即Data+CRC组合)
* @return
* Data
*/
public static String GetDataFromToken(String Token)
{
int length=Token.length();
return Token.substring(0, length-8);
}
/**
* 将CRC加入data尾部
* @param
* data
* @return
* Token(即Data+CRC组合)
*/
public static String AddCRCToken(String data)
{
return data+GetCRC(data);
}
/**
* 检验数据是否正确
* @param
* Token
* @return
* True or False
*/
public static boolean CheckCRCToken(String Token)
{
if( GetCRC(GetDataFromToken(Token)).compareTo(GetCRCFromToken(Token))==0)return true;
else return false;
}
// public static void main(String[] args)
// {
// String string="aa";
// System.out.println(string+":"+AddCRCToken(string));
// System.out.println("GetCRC:"+GetCRC(string));
// System.out.println("GetData:"+GetData(AddCRCToken(string)));
// System.out.println("GetCRCToken:"+GetCRCToken(AddCRCToken(string)));
// System.out.println(CheckCRCToken(AddCRCToken("aa")));
//
//// CRC32 crc =new CRC32();
//// crc.update("aa".getBytes());
////
//// String a= Long.toBinaryString(crc.getValue());
//// System.out.println(a);
//// System.out.println(a.length());
//
// }
}