Java UDP實現聊天功能代碼


  我以前經常寫的是基於TCP的網絡編程,由於TCP建立連接鼻血要經過三次握手連接,服務器端需要阻塞式等待客戶端的連接。而UDP則是可以直接向目的地址的目的端口上發送數據包,由於它只負責發送出去就好,不管對方是否正確接受到與否,所以當網絡性能不好時它容易出現丟包的問題。(注意:UDP是基於數據報為單位進行傳輸的,而TCP是一種基於流進行傳輸的)

  但是UDP很好的模擬了我們呢平時聊天的方式,可以很好的實現連續多次發送和接受,也就是簡單的QQ聊天的功能。

  現在來簡要介紹Java中有關UDP編程相關的類:

  一個是DatagramPacket,主要用來將數據字節填充到UDP數據報中,用來解包接受數據的,用來收和發UDP數據報。一個是DatagramSocket主要用來是建立客戶端和服務器端,用來接受和發送數據報數據的。

  (1)DatagramPacket類

  UDP首部向IP首部添加了8個字節,包含了源端口和目標端口,IP首部以后內容的長度和校驗和,最多有65507個字節數。UDP所使用的端口和TCP使用的端口不一樣的,是一個final類。

  對於接受數據,將接受到的數據存儲到DatagramPacket,然后從該對象中讀取數據。

  對於發送數據,將發送的數據先存到DatagramPacket中,然后將該對象發送。

 

  接受數據報構造函數:
  DatagramPacket(byte[] buffer,int length)
  DatagramPacket(byte[] buffer,int offset,int length)
  socket將接受到的數據部分存儲到buffer,一般buffer的大小最多定義為8192或者512大小即可
 
  發送數據報構造函數:
  由於DatagramPacket將數據填充到UDP數據報中,而數據報需要源端口和目標端口,客戶端一般創建的端口是匿名的,會在填充的過程中自動的加上,而源端口必須要首先顯式的在    DatagramPacket中設置,這樣才能填充到UDP數據報中。 發送數據都必須要把數據以字節形式發送。以API 1.6
  DatagramPacket(byte[] buffer,int length,InetAddress dest,int port)
  DatagramPacket(byte[] buffer,int offset,int length,InetAddress dest,int port)
  DatagramPacket(byte[] buffer,int length,SocketAddress dest)
  DatagramPacket(byte[] buffer,int offset,int length,SocketAddress dest)
   注意:SocketAddress是一個抽象類,主要保存了主機名、IP和端口號,
       一般可以SocketAddress address=new InetSocketAddress("www.baidu.com",2000)
       InetAddress只是用來保存主機名和IP的。
  InetAddress getAddress()、getPort()獲取發送數據目標地址、端口和接受到數據的源地址、端口
  SocketAddress getSocketAddress()(最常用的)一樣的意思。
 
  利用 getData()獲取接受到的數據報數據的字節數組,一般利用
  String res=new String(packet.getData(),"ASCII")或
  String s=new String(packet.getData(),packet.getOffset(),packet.getLength(),"UTF-8");
  獲取數據getLength()返回UDP中數據的字節數。getOffset()數據報中數據開始的點。
 
  
  對於已經構造好的DatagramPacket,可以在發送之前更改它的一些狀態。修改數據報的屬性,一般是先創建一個接受數據報的構造函數,然后對其報進行更改屬性。
  setData(byte[] data)
  setData(byte[] data,int offset,int length)  可以用來連續發送大量的數據塊
  setAddress(InetAddress remote)
  setPort(int port)
  setAddress(SocketAddress remote)相當於上面兩個方法。可以利用這些方法來設置一個數據報發送不同的ip和端口。
  setLength(int length)設置包的長度,主要是指定緩沖區中 將要發送的字節數,或用來 將要接收數據的包數據緩沖區的字節數。
  
  (2)DatagramSocket類
  在UDP中沒有明顯的客戶端類和服務器端類,客戶端既可以發消息也可以接受消息。均在創建的過程會有SocketException異常。創建UDP客戶端構造器
  DatagramSocket();創建一個對於客戶端來說匿名的端口,發送UDP的過程會自動加上該端口號,服務器接受消息也會按照該端口號發送。
  創建UDP服務器構造器
  DatagramSocket(int port)
  DatagramSocket(int port,InetAddress interface);用於一個主機有多個網絡接口的時候
  DatagramSocket(SocketAddress interface)
 
  發送數據報
  直接調用send(DatagramPacket dp),異常有IOException
  接受數據報
  receive( DatagramPacket dp ); 異常有IOException
  從網絡中接受一個UDP數據報,存儲在某一個DatagramPacket。在數據未到達之前會一直阻塞后面的運行,一般在無限循環中接受。
 
  管理連接
  connect(InetAddress host,int port)來設置其只對指定的遠程主機和指定遠程的接受和發送包
  getPort()、getInetAddress()返回其連接的遠程主機。一般在接受到消息后,需要調用
  packet.getSocketAddress(),獲取遠程主機基本信息

   以下是我寫的簡單的一個聊天程序:

Send_Thread.java

package Chat_UDP;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.Scanner;

public class Send_Thread extends Thread{
    
    //發送的socket端
    private DatagramSocket sender = null;
    //待發送的目標地址
    private InetSocketAddress address = null;
    //從鍵盤輸入
    Scanner scan = new Scanner(System.in);
    
    public Send_Thread(DatagramSocket sender,InetSocketAddress address)
    {
        this.sender = sender;
        this.address = address;
    }
    
    @Override
    public void run() {
        // TODO Auto-generated method stub
        try
        {
            while(true)
            {
                //輸入待發送的內容
                String input = scan.nextLine();
                if(input.equals("exit"))
                    break;
                byte[] data = null;
                data = input.getBytes("UTF-8");
                //創建UDP數據報
                DatagramPacket pack = new DatagramPacket(data, data.length,address);
                
                sender.send(pack);    
            }
            
            System.out.println("Exit!");
            
        }catch(IOException e)
        {
            System.out.println("IOException");
        }
    }

}

 

Receive_Thread.java

package Chat_UDP;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class Receive_Thread extends Thread {
    
    private static final int MAX_RECEIVE_BUFFER = 1024;
    private DatagramSocket server;
    private DatagramPacket packet;
    byte[] buffer = new byte[MAX_RECEIVE_BUFFER];
    
    public Receive_Thread(DatagramSocket server)
    {
        this.server = server;
        packet = new DatagramPacket(buffer, buffer.length);
    }
    
    @Override
    public void run() {
        // TODO Auto-generated method stub
        try
        {
            while(true)
            {
                //接收數據包
                server.receive(packet);
                String s = new String(packet.getData(),packet.getOffset(),packet.getLength(),"UTF-8");
                System.out.println(packet.getAddress()+" at port "+packet.getPort()+"  Says :"+s);
                packet.setLength(buffer.length);
            }
        }
        catch(IOException e)
        {
            System.out.println("IOException");
        }
    }
}

 

Chat_Client.java

 1 package Chat_UDP;
 2 
 3 import java.net.DatagramSocket;
 4 import java.net.InetSocketAddress;
 5 
 6 public class Chat_Client {
 7     
 8     private static final int DEST_PORT = 9000;
 9     private static final int SEND_PORT = 10000;
10     private static final int RECE_PORT = 8888;
11     private static final String IP = "127.0.0.1";
12     
13     public static void main(String[] args)
14     {
15         try{
16             Send_Thread send_thread = null;
17             Receive_Thread rece_thread = null;
18             InetSocketAddress address = null;
19             //創建待接受數據包的目的機的端口號和IP地址
20             address = new InetSocketAddress(IP, DEST_PORT);
21             //創建發送的Socket端
22             DatagramSocket sendsocket = new DatagramSocket(SEND_PORT);
23             //創建接受的Socket端
24             DatagramSocket recesocket = new DatagramSocket(RECE_PORT);
25             //發送線程建立
26             send_thread = new Send_Thread(sendsocket, address);
27             //接受線程的建立
28             rece_thread = new Receive_Thread(recesocket);
29             
30             send_thread.start();
31             rece_thread.start();
32             
33         }catch(Exception e)
34         {
35             System.out.println("Exception!");
36         }
37     
38     }
39     
40 
41 }

 

 Chat_Server.java

 1 package Chat_UDP;
 2 
 3 import java.net.DatagramSocket;
 4 import java.net.InetSocketAddress;
 5 
 6 public class Chat_Server {
 7     
 8     private static final int DEST_PORT = 8888;
 9     private static final int SEND_PORT = 10001;
10     private static final int RECE_PORT = 9000;
11     private static final String IP = "127.0.0.1";
12     
13     public static void main(String[] args)
14     {
15         try{
16             Send_Thread send_thread = null;
17             Receive_Thread rece_thread = null;
18             InetSocketAddress address = null;
19             //創建待接受數據包的目的機的端口號和IP地址
20             address = new InetSocketAddress(IP, DEST_PORT);
21             //創建發送的Socket端
22             DatagramSocket sendsocket = new DatagramSocket(SEND_PORT);
23             //創建接受的Socket端
24             DatagramSocket recesocket = new DatagramSocket(RECE_PORT);
25             //發送線程建立
26             send_thread = new Send_Thread(sendsocket, address);
27             //接受線程的建立
28             rece_thread = new Receive_Thread(recesocket);
29             send_thread.start();
30             rece_thread.start();
31         }catch(Exception e)
32         {
33             System.out.println("Exception!");
34         }
35     
36     }
37     
38 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM