久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

讀懂Java中的Socket編程

 codingparty 2015-03-08

Socket,又稱為套接字,Socket是計(jì)算機(jī)網(wǎng)絡(luò)通信的基本的技術(shù)之一,。如今大多數(shù)基于網(wǎng)絡(luò)的軟件,,如瀏覽器,即時(shí)通訊工具甚至是P2P下載都是基于Socket實(shí)現(xiàn)的,。本文會(huì)介紹一下基于TCP/IP的Socket編程,,并且如何寫一個(gè)客戶端/服務(wù)器程序。

餐前甜點(diǎn)

Unix的輸入輸出(IO)系統(tǒng)遵循Open-Read-Write-Close這樣的操作范本,。當(dāng)一個(gè)用戶進(jìn)程進(jìn)行IO操作之前,,它需要調(diào)用Open來(lái)指定并獲取待操作文件或設(shè)備讀取或?qū)懭氲臋?quán)限。一旦IO操作對(duì)象被打開(kāi),,那么這個(gè)用戶進(jìn)程可以對(duì)這個(gè)對(duì)象進(jìn)行一次或多次的讀取或?qū)懭氩僮?。Read操作用來(lái)從IO操作對(duì)象讀取數(shù)據(jù),并將數(shù)據(jù)傳遞給用戶進(jìn)程,。Write操作用來(lái)將用戶進(jìn)程中的數(shù)據(jù)傳遞(寫入)到IO操作對(duì)象,。 當(dāng)所有的Read和Write操作結(jié)束之后,用戶進(jìn)程需要調(diào)用Close來(lái)通知系統(tǒng)其完成對(duì)IO對(duì)象的使用,。

在Unix開(kāi)始支持進(jìn)程間通信(InterProcess Communication,,簡(jiǎn)稱IPC)時(shí),IPC的接口就設(shè)計(jì)得類似文件IO操作接口,。在Unix中,,一個(gè)進(jìn)程會(huì)有一套可以進(jìn)行讀取寫入的IO描述符。IO描述符可以是文件,,設(shè)備或者是通信通道(socket套接字),。一個(gè)文件描述符由三部分組成:創(chuàng)建(打開(kāi)socket),讀取寫入數(shù)據(jù)(接受和發(fā)送到socket)還有銷毀(關(guān)閉socket),。

在Unix系統(tǒng)中,,類BSD版本的IPC接口是作為TCP和UDP協(xié)議之上的一層進(jìn)行實(shí)現(xiàn)的。消息的目的地使用socket地址來(lái)表示。一個(gè)socket地址是由網(wǎng)絡(luò)地址和端口號(hào)組成的通信標(biāo)識(shí)符,。

進(jìn)程間通信操作需要一對(duì)兒socket,。進(jìn)程間通信通過(guò)在一個(gè)進(jìn)程中的一個(gè)socket與另一個(gè)進(jìn)程中得另一個(gè)socket進(jìn)行數(shù)據(jù)傳輸來(lái)完成,。當(dāng)一個(gè)消息執(zhí)行發(fā)出后,,這個(gè)消息在發(fā)送端的socket中處于排隊(duì)狀態(tài),直到下層的網(wǎng)絡(luò)協(xié)議將這些消息發(fā)送出去,。當(dāng)消息到達(dá)接收端的socket后,,其也會(huì)處于排隊(duì)狀態(tài),直到接收端的進(jìn)程對(duì)這條消息進(jìn)行了接收處理,。

TCP和UDP通信

關(guān)于socket編程我們有兩種通信協(xié)議可以進(jìn)行選擇,。一種是數(shù)據(jù)報(bào)通信,另一種就是流通信,。

數(shù)據(jù)報(bào)通信

數(shù)據(jù)報(bào)通信協(xié)議,,就是我們常說(shuō)的UDP(User Data Protocol 用戶數(shù)據(jù)報(bào)協(xié)議)。UDP是一種無(wú)連接的協(xié)議,,這就意味著我們每次發(fā)送數(shù)據(jù)報(bào)時(shí),,需要同時(shí)發(fā)送本機(jī)的socket描述符和接收端的socket描述符。因此,,我們?cè)诿看瓮ㄐ艜r(shí)都需要發(fā)送額外的數(shù)據(jù),。

流通信

流通信協(xié)議,也叫做TCP(Transfer Control Protocol,,傳輸控制協(xié)議),。和UDP不同,TCP是一種基于連接的協(xié)議,。在使用流通信之前,,我們必須在通信的一對(duì)兒socket之間建立連接。其中一個(gè)socket作為服務(wù)器進(jìn)行監(jiān)聽(tīng)連接請(qǐng)求,。另一個(gè)則作為客戶端進(jìn)行連接請(qǐng)求,。一旦兩個(gè)socket建立好了連接,他們可以單向或雙向進(jìn)行數(shù)據(jù)傳輸,。

讀到這里,,我們多少有這樣的疑問(wèn),我們進(jìn)行socket編程使用UDP還是TCP呢,。選擇基于何種協(xié)議的socket編程取決于你的具體的客戶端-服務(wù)器端程序的應(yīng)用場(chǎng)景,。下面我們簡(jiǎn)單分析一下TCP和UDP協(xié)議的區(qū)別,或許可以幫助你更好地選擇使用哪種,。

在UDP中,,每次發(fā)送數(shù)據(jù)報(bào)時(shí),需要附帶上本機(jī)的socket描述符和接收端的socket描述符。而由于TCP是基于連接的協(xié)議,,在通信的socket對(duì)之間需要在通信之前建立連接,,因此會(huì)有建立連接這一耗時(shí)存在于TCP協(xié)議的socket編程。

在UDP中,,數(shù)據(jù)報(bào)數(shù)據(jù)在大小上有64KB的限制,。而TCP中也不存在這樣的限制。一旦TCP通信的socket對(duì)建立了連接,,他們之間的通信就類似IO流,,所有的數(shù)據(jù)會(huì)按照接受時(shí)的順序讀取。

UDP是一種不可靠的協(xié)議,,發(fā)送的數(shù)據(jù)報(bào)不一定會(huì)按照其發(fā)送順序被接收端的socket接受,。然后TCP是一種可靠的協(xié)議。接收端收到的包的順序和包在發(fā)送端的順序是一致的,。

簡(jiǎn)而言之,,TCP適合于諸如遠(yuǎn)程登錄(rlogin,telnet)和文件傳輸(FTP)這類的網(wǎng)絡(luò)服務(wù)。因?yàn)檫@些需要傳輸?shù)臄?shù)據(jù)的大小不確定,。而UDP相比TCP更加簡(jiǎn)單輕量一些,。UDP用來(lái)實(shí)現(xiàn)實(shí)時(shí)性較高或者丟包不重要的一些服務(wù)。在局域網(wǎng)中UDP的丟包率都相對(duì)比較低,。

Java中的socket編程

下面的部分我將通過(guò)一些示例講解一下如何使用socket編寫客戶端和服務(wù)器端的程序,。

注意:在接下來(lái)的示例中,我將使用基于TCP/IP協(xié)議的socket編程,,因?yàn)檫@個(gè)協(xié)議遠(yuǎn)遠(yuǎn)比UDP/IP使用的要廣泛,。并且所有的socket相關(guān)的類都位于java.net包下,所以在我們進(jìn)行socket編程時(shí)需要引入這個(gè)包,。

客戶端編寫

開(kāi)啟Socket

如果在客戶端,,你需要寫下如下的代碼就可以打開(kāi)一個(gè)socket。

String host = "127.0.0.1";
int port = 8919;
Socket client = new Socket(host, port);

上面代碼中,,host即客戶端需要連接的機(jī)器,,port就是服務(wù)器端用來(lái)監(jiān)聽(tīng)請(qǐng)求的端口。在選擇端口時(shí),,需要注意一點(diǎn),,就是0~1023這些端口都已經(jīng)被系統(tǒng)預(yù)留了。這些端口為一些常用的服務(wù)所使用,,比如郵件,,F(xiàn)TP和HTTP。當(dāng)你在編寫服務(wù)器端的代碼,,選擇端口時(shí),,請(qǐng)選擇一個(gè)大于1023的端口,。

寫入數(shù)據(jù)

接下來(lái)就是寫入請(qǐng)求數(shù)據(jù),我們從客戶端的socket對(duì)象中得到OutputStream對(duì)象,,然后寫入數(shù)據(jù)后,。很類似文件IO的處理代碼。

public class ClientSocket {
  public static void main(String args[]) {
        String host = "127.0.0.1";
        int port = 8919;
        try {
          Socket client = new Socket(host, port);
          Writer writer = new OutputStreamWriter(client.getOutputStream());
          writer.write("Hello From Client");
          writer.flush();
          writer.close();
          client.close();
        } catch (IOException e) {
          e.printStackTrace();
        }
    }
  
}

關(guān)閉IO對(duì)象

類似文件IO,,在讀寫數(shù)據(jù)完成后,,我們需要對(duì)IO對(duì)象進(jìn)行關(guān)閉,以確保資源的正確釋放,。

服務(wù)器端編寫

打開(kāi)服務(wù)器端的socket

int port = 8919;
ServerSocket server = new ServerSocket(port);
Socket socket = server.accept();

上面的代碼創(chuàng)建了一個(gè)服務(wù)器端的socket,,然后調(diào)用accept方法監(jiān)聽(tīng)并獲取客戶端的請(qǐng)求socket,。accept方法是一個(gè)阻塞方法,,在服務(wù)器端與客戶端之間建立聯(lián)系之前會(huì)一直等待阻塞。

讀取數(shù)據(jù)

通過(guò)上面得到的socket對(duì)象獲取InputStream對(duì)象,,然后安裝文件IO一樣讀取數(shù)據(jù)即可,。這里我們將內(nèi)容打印出來(lái)。

public class ServerClient {
  public static void main(String[] args) {
        int port = 8919;
        try {
            ServerSocket server = new ServerSocket(port);
                Socket socket = server.accept();
            Reader reader = new InputStreamReader(socket.getInputStream());
            char chars[] = new char[1024];
            int len;
            StringBuilder builder = new StringBuilder();
            while ((len=reader.read(chars)) != -1) {
               builder.append(new String(chars, 0, len));
            }
            System.out.println("Receive from client message=: " + builder);
            reader.close();
            socket.close();
            server.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
  }
}

關(guān)閉IO對(duì)象

還是不能忘記的,,最后需要正確地關(guān)閉IO對(duì)象,,以確保資源的正確釋放。

附注一個(gè)例子

這里我們?cè)黾右粋€(gè)例子,,使用socket實(shí)現(xiàn)一個(gè)回聲服務(wù)器,,就是服務(wù)器會(huì)將客戶端發(fā)送過(guò)來(lái)的數(shù)據(jù)傳回給客戶端。代碼很簡(jiǎn)單,。

import java.io.*;
import java.net.*;
public class EchoServer {
    public static void main(String args[]) {
        // declaration section:
        // declare a server socket and a client socket for the server
        // declare an input and an output stream
        ServerSocket echoServer = null;
        String line;
        DataInputStream is;
        PrintStream os;
        Socket clientSocket = null;
        // Try to open a server socket on port 9999
        // Note that we can't choose a port less than 1023 if we are not
        // privileged users (root)
        try {
           echoServer = new ServerSocket(9999);
        }
        catch (IOException e) {
           System.out.println(e);
        }
        // Create a socket object from the ServerSocket to listen and accept 
        // connections.
        // Open input and output streams
        try {
               clientSocket = echoServer.accept();
               is = new DataInputStream(clientSocket.getInputStream());
               os = new PrintStream(clientSocket.getOutputStream());
               // As long as we receive data, echo that data back to the client.
               while (true) {
                 line = is.readLine();
                 os.println(line);
               }
        } catch (IOException e) {
               System.out.println(e);
            }
        }
}

編譯運(yùn)行上面的代碼,,進(jìn)行如下請(qǐng)求,就可以看到客戶端請(qǐng)求攜帶的數(shù)據(jù)的內(nèi)容,。

15:00 $ curl http://127.0.0.1:9999/?111
GET /?111 HTTP/1.1
User-Agent: curl/7.37.1
Host: 127.0.0.1:9999
Accept: */*

總結(jié)

進(jìn)行客戶端-服務(wù)器端編程還是比較有趣的,,同時(shí)在Java中進(jìn)行socket編程要比其他語(yǔ)言(如C)要簡(jiǎn)單快速編寫。

java.net這個(gè)包里面包含了很多強(qiáng)大靈活的類供開(kāi)發(fā)者進(jìn)行網(wǎng)絡(luò)編程,,在進(jìn)行網(wǎng)絡(luò)編程中,,建議使用這個(gè)包下面的API。同時(shí)Sun.*這個(gè)包也包含了很多的網(wǎng)絡(luò)編程相關(guān)的類,,但是不建議使用這個(gè)包下面的API,,因?yàn)檫@個(gè)包可能會(huì)改變,另外這個(gè)包不能保證在所有的平臺(tái)都有包含,。

原文信息

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn),。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購(gòu)買等信息,,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多