網(wǎng)絡(luò)編程:TCP、UDP及Socket

TCP/IP協(xié)議

IP、TCP、UDP 都是TCP/IP協(xié)議的一部分。而Socket是應(yīng)用層與TCP/IP協(xié)議通信抽象出來的接口。


TCP/IP.jpg

TCP/IP(Transmission Control Protocol/Internet Protocol)即傳輸控制協(xié)議/網(wǎng)間協(xié)議,是一個工業(yè)標(biāo)準(zhǔn)的協(xié)議集,它是為廣域(WANs)設(shè)計的。包括運輸層、網(wǎng)絡(luò)層、鏈路層。

TCP與UDP的區(qū)別

TCP

  1. TCP面向連接(三次握手);UDP是無連接的,即發(fā)送數(shù)據(jù)之前不需要建立連接。
  2. TCP傳輸可靠而UDP不可靠。也就是說,通過TCP連接傳送的數(shù)據(jù),無差錯,不丟失,不重復(fù),且按序到達;而UDP則不保證,可能丟包,也不按順序到達。因此UDP更快,效率高,TCP相反。
  3. TCP面向字節(jié)流,實際上是TCP把數(shù)據(jù)看成一連串無結(jié)構(gòu)的字節(jié)流。UDP是面向報文的。
  4. 通信方式:每一條TCP連接只能是點到點的;UDP支持一對一,一對多,多對一和多對多的交互通信。
  5. 基于以上這些區(qū)別,因此使用場景不同。TCP用在瀏覽器(Http)、文件傳輸(FTP)、接發(fā)郵件(SMTP,POP)、遠程登錄(telnet、ssh)。UDP用在視頻通話、語音通話等,適用于多播和廣播的應(yīng)用場景。

總之,TCP傳播數(shù)據(jù)準(zhǔn)確但速度較慢,用在文件傳輸?shù)葘?zhǔn)確性要求較高的地方。UDP相反,用在視頻流等大流量對速度要求較高的地方。

TCP和UDP的Socket實現(xiàn)(JAVA)

Java為Socket編程封裝了幾個重要的類。其中Socket和ServerSocket用于TCP通信。DatagramSocket和DatagramPacket用于UDP通信。


socket.png

基于TCP的Socket編程

Server端
服務(wù)器端首先實例化ServerSocket對象,然后為其綁定一個本機地址,并開始監(jiān)聽。一直阻塞狀態(tài)下等待客戶端請求,當(dāng)獲得客戶端連接請求后,返回一個socket對象。然后用這個socket接收一條消息,并發(fā)送一條消息。代碼如下:

package com.chenxuri.java.network;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * Created by chenxuri on 2017/12/21.
 */
public class SocketTcpServer {
    public static void main(String[] args) {
        try {
            ServerSocket serverSocket = new ServerSocket(8888);
            System.out.println("Connecting to client ...");

            /*
            接收客戶端數(shù)據(jù)
             */
            Socket socket = serverSocket.accept();
            InputStream inputStream = socket.getInputStream();
            BufferedReader socketIn = new BufferedReader(new InputStreamReader(inputStream));
            String temp;
            while ((temp = socketIn.readLine()) != null) {
                System.out.println(temp);
            }

            /*
            發(fā)送數(shù)據(jù)
             */
            OutputStream outputStream = socket.getOutputStream();
            PrintWriter socketOut = new PrintWriter(outputStream);
            socketOut.print("Hi,I have received your message!");
            socketOut.flush();

            socketOut.close();
            socketIn.close();
            socket.close();
            serverSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Client端
客戶端首先實例化一個socket對象,用這個對象連接服務(wù)器端。連接成功后,發(fā)送一條消息,然后等待接收一條消息。代碼如下:

package com.chenxuri.java.network;

import java.io.*;
import java.net.InetSocketAddress;
import java.net.Socket;


/**
 * Created by chenxuri on 2017/12/21.
 */
public class SocketTcpClient {
    public static void main(String[] args) {
        try {
            Socket socket = new Socket();
            /*
            設(shè)置地址和連接超時時間,有的地方說不設(shè)置連接時間可能會造成無限期阻塞。
            其實不會,因為操作系統(tǒng)底層有超時限制,windows是20秒。
            但仍建議設(shè)置一個較短的時間,尤其是需要頻繁連接的時候。
             */
            socket.connect(new InetSocketAddress("127.0.0.1",8888), 5*1000);
            //設(shè)置讀取超時時間,該時間若不設(shè)置,服務(wù)器等出現(xiàn)問題時可能會一直處于阻塞狀態(tài)。
            socket.setSoTimeout(10*1000);

            /*
            往服務(wù)端發(fā)送數(shù)據(jù)
             */
            OutputStream outputStream  = socket.getOutputStream();
            PrintWriter socketOut = new PrintWriter(outputStream);
            String str = "Hello,I come from client!";
            socketOut.write(str);
            socketOut.flush();
            socket.shutdownOutput();  //半關(guān)閉,告訴服務(wù)端發(fā)送完畢,可以接受輸入過來的數(shù)據(jù)

             /*
            接收回應(yīng)數(shù)據(jù)
             */
            InputStream inputStream = socket.getInputStream();
            BufferedReader socketIn = new BufferedReader(new InputStreamReader(inputStream));
            String temp;
            while ((temp = socketIn.readLine()) != null) {
                System.out.println(temp);
            }

            socketIn.close();
            socketOut.close();
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

基于UDP的Socket編程

Server端
服務(wù)器端首先實例化DatagramSocket對象,然后為其綁定一個端口,并開始監(jiān)聽。一直阻塞狀態(tài)下等待從客戶端接收數(shù)據(jù)報。然后從數(shù)據(jù)報中獲取數(shù)據(jù)報的源地址,然后用這個源地址作為目的地址打包一個數(shù)據(jù)報,然后發(fā)送出去。代碼如下:

package com.chenxuri.java.network;

import java.io.*;
import java.net.*;

/**
 * Created by chenxuri on 2017/12/21.
 */
public class SocketUdpServer {
    public static void main(String[] args) {
        try {
            DatagramSocket socket = new DatagramSocket(8888);

            /*
            接收客戶端的數(shù)據(jù)
             */
            byte[] bytes = new byte[1024];
            DatagramPacket packet = new DatagramPacket(bytes,bytes.length);
            socket.receive(packet);
            String receiveStr = new String(bytes);
            System.out.println("From client: " + receiveStr);

            /*
            發(fā)送回應(yīng)數(shù)據(jù)
             */
            int port = packet.getPort();
            InetAddress addr = packet.getAddress();
            String sendStr = "Hello! I'm Server";
            byte[] sendBuf = sendStr.getBytes();
            DatagramPacket sendPacket = new DatagramPacket(sendBuf , sendBuf.length , addr , port );
            socket.send(sendPacket);
            socket.close();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Client端
客戶端首先實例化一個DatagramSocket對象。利用服務(wù)器地址和端口號作為目的地址打包一個數(shù)據(jù)報,并發(fā)送。然后等待從服務(wù)器回復(fù)的數(shù)據(jù)報。代碼如下:

package com.chenxuri.java.network;

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

/**
 * Created by chenxuri on 2017/12/21.
 */
public class SocketUdpClient {
    public static void main(String[] args) {
        try {
            DatagramSocket socket = new DatagramSocket();

            /*
            發(fā)送數(shù)據(jù)
             */
            String sendStr = "I'm client, this is the message for server.";
            byte[] bytes = sendStr.getBytes();
            DatagramPacket packet = new DatagramPacket(bytes,bytes.length);
            packet.setSocketAddress(new InetSocketAddress("127.0.0.1",8888));
            socket.send(packet);

            /*
            接收返回數(shù)據(jù)
             */
            byte[] backbuf = new byte[1024];
            DatagramPacket backPacket = new DatagramPacket(backbuf, backbuf.length);
            socket.receive(backPacket);
            System.out.println("From server: "+ new String(backbuf));

            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

以上代碼都經(jīng)過親自測試,可以運行。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 個人認為,Goodboy1881先生的TCP /IP 協(xié)議詳解學(xué)習(xí)博客系列博客是一部非常精彩的學(xué)習(xí)筆記,這雖然只是...
    貳零壹柒_fc10閱讀 5,196評論 0 8
  • 1.這篇文章不是本人原創(chuàng)的,只是個人為了對這部分知識做一個整理和系統(tǒng)的輸出而編輯成的,在此鄭重地向本文所引用文章的...
    SOMCENT閱讀 13,377評論 6 174
  • 計算機網(wǎng)絡(luò)七層模型中,傳輸層有兩個重要的協(xié)議:(1)用戶數(shù)據(jù)報協(xié)議UDP (User Datagram Proto...
    Q南南南Q閱讀 1,868評論 0 3
  • 轉(zhuǎn)。。。。。。。。 SOCKET,TCP/UDP,HTTP,FTP (一)TCP/UDP,SOCKET,HTTP,...
    zeqinjie閱讀 3,386評論 1 53
  • 晚上閑著沒事兒,坐在床上刷手機,刷著刷著就刷出了一則“勁爆消息”:,當(dāng)時我就怒了,這些人擱古代就應(yīng)被凌遲處死,放到...
    魚朋朋閱讀 248評論 0 1

友情鏈接更多精彩內(nèi)容