Java中UDP通信連接實現(xiàn)

TCP與UDP的主要區(qū)別:

TCP—傳輸控制協(xié)議,提供的是面向連接浸间、可靠的字節(jié)流服務(wù)拒逮。當(dāng)客戶和服務(wù)器彼此交換數(shù)據(jù)前伐蒋,必須先在雙方之間建立一個TCP連接物臂,之后才能傳輸數(shù)據(jù)舷蟀。TCP提供超時重發(fā)池凄,丟棄重復(fù)數(shù)據(jù)贮尖,檢驗數(shù)據(jù)蹬蚁,流量控制等功能薇组,保證數(shù)據(jù)能從一端傳到另一端
UDP—用戶數(shù)據(jù)報協(xié)議外臂,是一個簡單的面向數(shù)據(jù)報的運輸層協(xié)議。UDP不提供可靠性律胀,它只是把應(yīng)用程序傳給IP層的數(shù)據(jù)報發(fā)送出去宋光,但是并不能保證它們能到達(dá)目的地。由于UDP在傳輸數(shù)據(jù)報前不用在客戶和服務(wù)器之間建立一個連接炭菌,且沒有超時重發(fā)等機(jī)制罪佳,故而傳輸速度很快.

在Java數(shù)據(jù)通信中UDP編程

UDP協(xié)議(用戶數(shù)據(jù)報協(xié)議)是無連接的、不可靠的黑低、無序的,速度快
進(jìn)行數(shù)據(jù)傳輸時赘艳,首先將要傳輸?shù)臄?shù)據(jù)定義成數(shù)據(jù)報(Datagram),大小限制在64k克握,在數(shù)據(jù)報中指明數(shù)據(jù)索要達(dá)到的Socket(主機(jī)地址和端口號)蕾管,然后再將數(shù)據(jù)報發(fā)送出去

DatagramPacket類:表示數(shù)據(jù)報包
DatagramSocket類:進(jìn)行端到端通信的類
服務(wù)器端實現(xiàn)步驟
① 創(chuàng)建DatagramSocket,指定端口號
② 創(chuàng)建DatagramPacket
③ 接受客戶端發(fā)送的數(shù)據(jù)信息
④ 讀取數(shù)據(jù)

public class UDPServer {
    public static void main(String[] args) throws IOException {
        /*
         * 接收客戶端發(fā)送的數(shù)據(jù)
         */
        //1.創(chuàng)建服務(wù)器端DatagramSocket菩暗,指定端口
        DatagramSocket socket=new DatagramSocket(8800);
        //2.創(chuàng)建數(shù)據(jù)報掰曾,用于接收客戶端發(fā)送的數(shù)據(jù)
        byte[] data =new byte[1024];//創(chuàng)建字節(jié)數(shù)組,指定接收的數(shù)據(jù)包的大小
        DatagramPacket packet=new DatagramPacket(data, data.length);
        //3.接收客戶端發(fā)送的數(shù)據(jù)
        System.out.println("****服務(wù)器端已經(jīng)啟動停团,等待客戶端發(fā)送數(shù)據(jù)");
        socket.receive(packet);//此方法在接收到數(shù)據(jù)報之前會一直阻塞
        //4.讀取數(shù)據(jù)
        String info=new String(data, 0, packet.getLength());
        System.out.println("我是服務(wù)器旷坦,客戶端說:"+info);

        /*
         * 向客戶端響應(yīng)數(shù)據(jù)
         */
        //1.定義客戶端的地址掏熬、端口號、數(shù)據(jù)
        InetAddress address=packet.getAddress();
        int port=packet.getPort();
        byte[] data2="歡迎您!".getBytes();
        //2.創(chuàng)建數(shù)據(jù)報塞蹭,包含響應(yīng)的數(shù)據(jù)信息
        DatagramPacket packet2=new DatagramPacket(data2, data2.length, address, port);
        //3.響應(yīng)客戶端
        socket.send(packet2);
        //4.關(guān)閉資源
        socket.close();
    }
}

客戶端實現(xiàn)步驟
① 定義發(fā)送信息
② 創(chuàng)建DatagramPacket孽江,包含將要發(fā)送的信息
③ 創(chuàng)建DatagramSocket
④ 發(fā)送數(shù)據(jù)

public class UDPClient {
    public static void main(String[] args) throws IOException {
        /*
         * 向服務(wù)器端發(fā)送數(shù)據(jù)
         */
        //1.定義服務(wù)器的地址、端口號番电、數(shù)據(jù)
        InetAddress address=InetAddress.getByName("localhost");
        int port=8800;
        byte[] data="用戶名:jinbin;密碼:1997".getBytes();
        //2.創(chuàng)建數(shù)據(jù)報岗屏,包含發(fā)送的數(shù)據(jù)信息
        DatagramPacket packet=new DatagramPacket(data, data.length, address, port);
        //3.創(chuàng)建DatagramSocket對象
        DatagramSocket socket=new DatagramSocket();
        //4.向服務(wù)器端發(fā)送數(shù)據(jù)報
        socket.send(packet);

        /*
         * 接收服務(wù)器端響應(yīng)的數(shù)據(jù)
         */
        //1.創(chuàng)建數(shù)據(jù)報,用于接收服務(wù)器端響應(yīng)的數(shù)據(jù)
        byte[] data2=new byte[1024];
        DatagramPacket packet2=new DatagramPacket(data2, data2.length);
        //2.接收服務(wù)器響應(yīng)的數(shù)據(jù)
        socket.receive(packet2);
        //3.讀取數(shù)據(jù)
        String reply=new String(data2, 0, packet2.getLength());
        System.out.println("我是客戶端漱办,服務(wù)器說:"+reply);
        //4.關(guān)閉資源
        socket.close();
    }
}

下面進(jìn)行測試
同樣的这刷,需要先啟動服務(wù)端再啟動客戶端
啟動完可以看到服務(wù)端控制臺顯示如下

image.png

下面來啟動客戶端
image.png

再來看看服務(wù)端
image.png

這樣就實現(xiàn)了服務(wù)端與單個客戶端的通信

下面來通過多線程實現(xiàn)服務(wù)端與多個客戶端的通信

服務(wù)器端線程處理類UDPServerThread

public class UDPServerThread extends Thread{
    DatagramPacket packet;
    DatagramSocket socket;

    public UDPServerThread(DatagramPacket packet, DatagramSocket socket) {
        super();
        this.packet = packet;
        this.socket = socket;
    }

    @Override
    public void run(){
        try {
            //獲取客戶端信息
            byte[] data = packet.getData();
            String info1 = new String(data, 0, packet.getLength());
            System.out.println("我是服務(wù)器,客戶端說:" + info1);
            //響應(yīng)客戶端
            InetAddress address = packet.getAddress();
            int port = packet.getPort();
            byte[] data1 = "歡迎您娩井!".getBytes();
            DatagramPacket packet1 = new DatagramPacket(data1, data1.length, address, port);
            socket.send(packet1);
        }catch (IOException e) {
            e.printStackTrace();
        }
    }
}

服務(wù)端代碼相應(yīng)改下

public class UDPServer {
    public static void main(String[] args) throws IOException {
        /*
         * 接收客戶端發(fā)送的數(shù)據(jù)
         */
        //1.創(chuàng)建服務(wù)器端DatagramSocket暇屋,指定端口
        DatagramSocket socket=new DatagramSocket(8800);
        //2.創(chuàng)建數(shù)據(jù)報,用于接收客戶端發(fā)送的數(shù)據(jù)
        byte[] data =new byte[1024];//創(chuàng)建字節(jié)數(shù)組洞辣,指定接收的數(shù)據(jù)包的大小
        System.out.println("****服務(wù)器啟動咐刨,等待客戶端連接****");
        int count=1;
        while(true) {
            DatagramPacket packet = new DatagramPacket(data, data.length);
            socket.receive(packet);
            UDPServerThread serverThread = new UDPServerThread(packet, socket);
            serverThread.start();
            System.out.println("客戶端數(shù)量:" + count++);
        }
    }
}

這里的socket.receive()如果不寫的話會產(chǎn)生死循環(huán)
同樣客戶端也是不用改

下面進(jìn)行測試

1.啟動服務(wù)端

image.png

2.啟動一個客戶端
image.png

3.服務(wù)端并沒有停止,并且接收到客戶端傳來的信息
image.png

4.再啟動下客戶端扬霜,控制臺顯示客戶端數(shù)量為2定鸟,證明可以與對個客戶端通信
image.png

注意:UDP多個客戶端通信的時候socket是不關(guān)閉的,我也試過關(guān)閉的話
會出異常Exception in thread "main" java.net.SocketException: socket closed
因為在UDPServer類的while是死循環(huán)著瓶,無法重新創(chuàng)建socket,所以這里不能關(guān)閉socket,否則無法進(jìn)行下一個客戶端的監(jiān)聽

總結(jié):

UDP相較于TCP联予,不需要進(jìn)行復(fù)雜的設(shè)定輸入輸出流,只需要設(shè)定數(shù)據(jù)報材原,即DatagramPacket沸久。而TCP的發(fā)送以及接收消息,是通過socket.getInputStream()或者getOutputStream()方法余蟹,而UDP是直接設(shè)置了卷胯,DatagramSocket,通過其send()或者receive()方法來接收或發(fā)送消息威酒。
TCP的關(guān)鍵組成有服務(wù)端的ServerSocket.accept()方法诵竭,這個方法是直到接收到了客戶端的連接才會返回一個Socket,用于接下來的輸入和輸出兼搏。

所以說,TCP的數(shù)據(jù)傳輸是需要提前連接沙郭、三方握手佛呻,數(shù)據(jù)傳輸非常安全。而UDP是不需要提前連接的病线,無需等待對方回答吓著,所以不保證數(shù)據(jù)不丟失鲤嫡。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市绑莺,隨后出現(xiàn)的幾起案子暖眼,更是在濱河造成了極大的恐慌,老刑警劉巖纺裁,帶你破解...
    沈念sama閱讀 212,222評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件诫肠,死亡現(xiàn)場離奇詭異,居然都是意外死亡欺缘,警方通過查閱死者的電腦和手機(jī)栋豫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,455評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來谚殊,“玉大人丧鸯,你說我怎么就攤上這事∧坌酰” “怎么了丛肢?”我有些...
    開封第一講書人閱讀 157,720評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長剿干。 經(jīng)常有香客問我蜂怎,道長,這世上最難降的妖魔是什么怨愤? 我笑而不...
    開封第一講書人閱讀 56,568評論 1 284
  • 正文 為了忘掉前任派敷,我火速辦了婚禮,結(jié)果婚禮上撰洗,老公的妹妹穿的比我還像新娘篮愉。我一直安慰自己,他們只是感情好差导,可當(dāng)我...
    茶點故事閱讀 65,696評論 6 386
  • 文/花漫 我一把揭開白布试躏。 她就那樣靜靜地躺著,像睡著了一般设褐。 火紅的嫁衣襯著肌膚如雪颠蕴。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,879評論 1 290
  • 那天助析,我揣著相機(jī)與錄音犀被,去河邊找鬼。 笑死外冀,一個胖子當(dāng)著我的面吹牛寡键,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播雪隧,決...
    沈念sama閱讀 39,028評論 3 409
  • 文/蒼蘭香墨 我猛地睜開眼西轩,長吁一口氣:“原來是場噩夢啊……” “哼员舵!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起藕畔,我...
    開封第一講書人閱讀 37,773評論 0 268
  • 序言:老撾萬榮一對情侶失蹤马僻,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后注服,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體韭邓,經(jīng)...
    沈念sama閱讀 44,220評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,550評論 2 327
  • 正文 我和宋清朗相戀三年祠汇,在試婚紗的時候發(fā)現(xiàn)自己被綠了仍秤。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,697評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡可很,死狀恐怖诗力,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情我抠,我是刑警寧澤苇本,帶...
    沈念sama閱讀 34,360評論 4 332
  • 正文 年R本政府宣布,位于F島的核電站菜拓,受9級特大地震影響瓣窄,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜纳鼎,卻給世界環(huán)境...
    茶點故事閱讀 40,002評論 3 315
  • 文/蒙蒙 一俺夕、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧贱鄙,春花似錦劝贸、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,782評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至瞎颗,卻和暖如春件甥,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背哼拔。 一陣腳步聲響...
    開封第一講書人閱讀 32,010評論 1 266
  • 我被黑心中介騙來泰國打工引有, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人倦逐。 一個月前我還...
    沈念sama閱讀 46,433評論 2 360
  • 正文 我出身青樓轿曙,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子导帝,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,587評論 2 350

推薦閱讀更多精彩內(nèi)容