UDP接收資料報
阿新 • • 發佈:2019-01-09
對於接受udp資料包,可以有如下另種設計:
第一,同UDP傳送端一樣,寫成一個助手類,然後每次將收到的結果給需要的地方。
另一種是,將udp接收端與其處理程式寫在同一個類中,即其受到資料之後就進行分析,然後做出判斷與處理。
分析
對於本應用程式來說,我才去了第二中方法。首先,該udp接收端是在應用程式例項化是就存在,直到應用程式死亡期結束生命。那麼從始至終我們只需要一個udp接受端。其次在設計udp接收端是,其接受的資料主要是字串,對字串做出相應處理的時間一般不會太長。而且UDP接收端接收到資料後要做出相應的操作,而且多數會用到呼叫它的類的相關方法。
實現
前面已將分析了,UDP接收端接收到資料後要做出相應的操作,而且多數會用到呼叫它的類的相關方法。所以udp接收端在例項化的時候,需要知道呼叫它的類的引用。
其次,接收端為阻塞方法,其應該單寫在一個執行緒中。
程式碼實現
Java程式碼- 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接收端的程式碼,一種會有一些類暫時還沒有給出,在之後會介紹到。程式碼也會隨程式中其他程式碼一起給出。