UDP接收数据报
作者:legend
QQ:158067568
对于接受udp数据包,可以有如下另种设计:
第一,同UDP发送端一样,写成一个助手类,然后每次将收到的结果给需要的地方。
另一种是,将udp接收端与其处理程序写在同一个类中,即其受到数据之后就进行分析,然后做出判断与处理。
分析
对于本应用程序来说,我才去了第二中方法。首先,该udp接收端是在应用程序实例化是就存在,直到应用程序死亡期结束生命。那么从始至终我们只需要一个udp接受端。其次在设计udp接收端是,其接受的数据主要是字符串,对字符串做出相应处理的时间一般不会太长。而且UDP接收端接收到数据后要做出相应的操作,而且多数会用到调用它的类的相关方法。
实现
前面已将分析了,UDP接收端接收到数据后要做出相应的操作,而且多数会用到调用它的类的相关方法。所以udp接收端在实例化的时候,需要知道调用它的类的引用。
其次,接收端为阻塞方法,其应该单写在一个线程中。
代码实现
package cn.edu.heut.zcl;
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 java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.JOptionPane;
import cn.edu.heut.helper.UDPSendHelper;
import cn.edu.heut.zcl.domain.UserInfo;
import cn.edu.heut.zcl.rtp.capture.AudioCapture;
import static cn.edu.heut.zcl.Constant.*;
/**
* 该类主要是一直循环等待着其他客户端发来的消息,监听端口是19881
* 发送端将采用广播的形式进行发送。
* @author zcl
*
*/
public class UDPReceiveSystemInfo extends Thread{
/**
* 大管家的引用
*/
private Master master ;
/**
* 接收者的套接字
*/
private DatagramSocket receiveSocket ;
private DatagramPacket receiveDatagramPacket ;
public UDPReceiveSystemInfo(Master master){
this.master = master ;
}
@Override
public void run() {
try {
receiveSocket = new DatagramSocket(UDPRECEIVESYSTEMINFO_UDP_RECEIVE_PORT);
} catch (SocketException e) {
e.printStackTrace();
}
while(master.isLive()){//如果程序还在运行,那么就一直循环监听
receiveDatagramPacket = new DatagramPacket(
new byte[UDPRECEIVESYSTEMINFO_UDP_RECEIVE_DP_LENGTH],UDPRECEIVESYSTEMINFO_UDP_RECEIVE_DP_LENGTH);
try {//此处接收发送来的数据报文
receiveSocket.receive(receiveDatagramPacket);
executeReceiveData(receiveDatagramPacket);
} catch (IOException e) {
e.printStackTrace();
}
}
if(!master.isLive()){
receiveSocket.close();
}
}
/**
* 处理发送来的数据
* @param 发送来的数据
*/
public void executeReceiveData(DatagramPacket receiveDP){
String receiveData = new String(receiveDP.getData()).trim();//得到发送过来的数据
String ipAddress = receiveDP.getAddress().getHostAddress();
// System.out.println("ipAddress:::::::: "+ipAddress);
if(receiveData.startsWith(CONTROL_MSG_ADD_A_CLIENT)){//如果是新添加一个客户端,执行以下操作
String name = findUserName(receiveData);
//将该客户端的信息添加到记录当前在线用户的list中
UserInfo newUser = new UserInfo();
newUser.setUserName(name);
newUser.setUserIP(receiveDP.getAddress());
master.currentOnLineUserList.add(newUser);
//在PhoneFrame的表格中添加该客户端信息。
String[] rowData = {name,ipAddress};
master.phoneFrame.defaultTableModel.addRow(rowData);
String localHostIP = null;
try {
localHostIP = InetAddress.getLocalHost().toString();
} catch (UnknownHostException e) {
e.printStackTrace();
}
//如果不是自己的话,之后再告诉这个新加入的客户端,我是谁,我的相关信息
if(!master.getUserName().equals(name) && !ipAddress.equals(localHostIP)){
String data = CONTROL_MSG_ADD_A_CLIENT_ECHO_INFO +CONTROL_MSG_USER_NAEM +master.getUserName() + CONTROL_MSG_END_USER_NAEM;
InetAddress destIPAddress = null;
destIPAddress = receiveDP.getAddress();
int destPort = UDPRECEIVESYSTEMINFO_UDP_RECEIVE_PORT;
new UDPSendHelper(data, destIPAddress, destPort).start();
}
}else if(receiveData.startsWith(CONTROL_MSG_LEAVE_THE_CLIENT)){//收到退出一个客户端,执行以下方法
// System.out.println(receiveData);
String name = findUserName(receiveData);
//将list中的该用户删除
for(int i=0 ;i<master.currentOnLineUserList.size();i++){
UserInfo ui = master.currentOnLineUserList.get(i);
String uiName = ui.getUserName();
InetAddress uiIp = ui.getUserIP() ;
if(uiName.equals(name) && uiIp.toString().equals(ipAddress)){//判断是否是同一个用户,删除该项,退出循环
master.currentOnLineUserList.remove(i);
break;
}
}
//将PhoneFrame表格中的信息删除
for(int i=0 ;i<master.phoneFrame.defaultTableModel.getRowCount();i++){//进行行遍历
String curTabUserName = (String) master.phoneFrame.defaultTableModel.getValueAt(i, 0);
String curTabUserIP = (String) master.phoneFrame.defaultTableModel.getValueAt(i, 1);
if(curTabUserName.equals(name) && curTabUserIP.equals(ipAddress)){
master.phoneFrame.defaultTableModel.removeRow(i);
break;
}
}
}else if(receiveData.startsWith(CONTROL_MSG_ADD_A_CLIENT_ECHO_INFO)){//如果是收到了该客户端发送给其他服务器的新添加一个客户端的回复信息,则根据回复信息,将该发送者信息添加入list,并且在表格中显示。
String name = findUserName(receiveData);
//将该客户端的信息添加到记录当前在线用户的list中
UserInfo newUser = new UserInfo();
newUser.setUserName(name);
newUser.setUserIP(receiveDP.getAddress());
master.currentOnLineUserList.add(newUser);
//在PhoneFrame的表格中添加该客户端信息。
String[] rowData = {name,ipAddress};
master.phoneFrame.defaultTableModel.addRow(rowData);
}else if(receiveData.startsWith(CONTROL_MSG_CONNECT_VOICE_REQUEST)){//如果收到的进行语音通讯请求,执行以下内容
if(!master.connectState.isConnecting()){//如果当前客户端没有通话,则执行以下操作
System.out.println("receiveData request:"+receiveDP.getAddress().toString());
int conJOP =JOptionPane.showConfirmDialog(null,ipAddress+"的来电,是否接听", "来电",
JOptionPane.YES_NO_OPTION);
InetAddress destAddress = receiveDP.getAddress();
int destPort = UDPRECEIVESYSTEMINFO_UDP_RECEIVE_PORT;
switch(conJOP){
case 0://接听来电
String acceptData = CONTROL_MSG_CONNECT_VOICE_ACCEPT;
new UDPSendHelper(acceptData, destAddress, destPort).start();
master.connectState.setConnecting(true);//设置当前连接为通话状态
//do something...
// new AudioCapture(master,ipAddress).start();
String port = RTP_CALLER_RECEIVE_VOICE_PORT;
new Thread(new AudioCapture(master,ipAddress,port)).start();//开启通话线程开始通话
break;
case 1://拒绝来电
String refuseData = CONTROL_MSG_CONNECT_VOICE_REFUSE;
new UDPSendHelper(refuseData, destAddress, destPort).start();
break;
}
}else{//如果当前客户端正在通话,则执行如下操作:告诉请求方,我正在通话,等会再打过来
String sendConnectingDate = CONTROL_MSG_STATE_CONNECTING;
InetAddress destAddress = receiveDP.getAddress();
int destPort = UDPRECEIVESYSTEMINFO_UDP_RECEIVE_PORT;
new UDPSendHelper(sendConnectingDate, destAddress, destPort).start();
}
}else if(receiveData.startsWith(CONTROL_MSG_CONNECT_VOICE_ACCEPT)){//刚刚发送的请求被接受。此为主叫方
//do something...
String port = RTP_CALLER_SEND_VOICE_PORT;
new Thread(new AudioCapture(master,ipAddress,port)).start();//开启通话线程开始通话
System.out.println("执行通话操作..");
}else if(receiveData.startsWith(CONTROL_MSG_CONNECT_VOICE_REFUSE) ){//刚刚发送的请求被拒绝
JOptionPane.showConfirmDialog(null,ipAddress+"拒绝您的来电", "拒绝来电",
JOptionPane.YES_OPTION);
}else if( receiveData.startsWith(CONTROL_MSG_STATE_CONNECTING)){//对方正在通话中,执行如下操作
JOptionPane.showConfirmDialog(null,ipAddress+"正在通话中,请稍后再拨", "提示", JOptionPane.YES_OPTION);
}
}
/**
* 从字符串str中寻找用户的用户名,如果存在返回用户名,不存在返回null。
* -用户名是包裹在名字控制字符中间的字符串。
* @param str
* @return uName 返回用户名
*/
public String findUserName(String str){
String uName = null ;
String msg =findFirstPatternString(CONTROL_MSG_USER_NAEM+"{1}.*"+CONTROL_MSG_END_USER_NAEM+"{1}", str);
uName = msg.substring(CONTROL_MSG_USER_NAEM.length(), msg.length()-CONTROL_MSG_END_USER_NAEM.length());//此处得到用户名字
return uName;
}
/**
* 查询msg中是否存在符合patternString的字符串,如果有返回第一个出现该字符串的数据,不存在返回null
* @param patternString 匹配字符串
* @param msg 查询字符串
* @return 结果
*/
public static String findFirstPatternString(String patternString,String msg){
String result = null ;
Pattern p = Pattern.compile(patternString);
Matcher m = p.matcher(msg);
if(m.find()){
result = m.group();
}
return result;
}
}
以上是udp接收端的代码,一种会有一些类暂时还没有给出,在之后会介绍到。代码也会随程序中其他代码一起给出。