Java開發之Socket編程詳解

来源:http://www.cnblogs.com/Jepson1218/archive/2016/02/02/5178792.html
-Advertisement-
Play Games

本文從3個方面對Socket編程進行詳解: 一,網路編程中兩個主要的問題 二,兩類傳輸協議:TCP;UDP 三,基於Socket的java網路編程 一,網路編程中兩個主要的問題 一個是如何準確的定位網路上一臺或多台主機,另一個就是找到主機後如何可靠高效的進行數據傳輸。 在TCP/IP協議中IP層主要


本文從3個方面對Socket編程進行詳解:


 

一,網路編程中兩個主要的問題

二,兩類傳輸協議:TCP;UDP

三,基於Socket的java網路編程


一,網路編程中兩個主要的問題

一個是如何準確的定位網路上一臺或多台主機,另一個就是找到主機後如何可靠高效的進行數據傳輸。

  在TCP/IP協議中IP層主要負責網路主機的定位,數據傳輸的路由,由IP地址可以唯一地確定Internet上的一臺主機。而TCP層則提供面嚮應用的可靠(tcp)的或非可靠(UDP)的數據傳輸機制,這是網路編程的主要對象,一般不需要關心IP層是如何處理數據的。

  目前較為流行的網路編程模型是客戶機/伺服器(C/S)結構。即通信雙方一方作為伺服器等待客戶提出請求並予以響應。客戶則在需要服務時向伺服器提出申請。伺服器一般作為守護進程始終運行,監聽網路埠,一旦有客戶請求,就會啟動一個服務進程來響應該客戶,同時自己繼續監聽服務埠,使後來的客戶也能及時得到服務。


二,兩類傳輸協議:TCP;UDP

  TCP是Tranfer Control Protocol的簡稱,是一種面向連接的保證可靠傳輸的協議。通過TCP協議傳輸,得到的是一個順序的無差錯的數據流。發送方和接收方的成對的兩個socket之間必須建立連接,以便在TCP協議的基礎上進行通信,當一個socket(通常都是server socket)等待建立連接時,另一個socket可以要求進行連接,一旦這兩個socket連接起來,它們就可以進行雙向數據傳輸,雙方都可以進行發送或接收操作。

  UDP是User Datagram Protocol的簡稱,是一種無連接的協議,每個數據報都是一個獨立的信息,包括完整的源地址或目的地址,它在網路上以任何可能的路徑傳往目的地,因此能否到達目的地,到達目的地的時間以及內容的正確性都是不能被保證的。

比較:

UDP:

1,每個數據報中都給出了完整的地址信息,因此無需要建立發送方和接收方的連接。

2,UDP傳輸數據時是有大小限制的,每個被傳輸的數據報必須限定在64KB之內。

3,UDP是一個不可靠的協議,發送方所發送的數據報並不一定以相同的次序到達接收方

TCP:

1,面向連接的協議,在socket之間進行數據傳輸之前必然要建立連接,所以在TCP中需要連接時間。

2,TCP傳輸數據大小限制,一旦連接建立起來,雙方的socket就可以按統一的格式傳輸大的數據。

3,TCP是一個可靠的協議,它確保接收方完全正確地獲取發送方所發送的全部數據。

應用:

1,TCP在網路通信上有極強的生命力,例如遠程連接(Telnet)和文件傳輸(FTP)都需要不定長度的數據被可靠地傳輸。但是可靠的傳輸是要付出代價的,對數據內容正確性的檢驗必然占用電腦的處理時間和網路的帶寬,因此TCP傳輸的效率不如UDP高。

2,UDP操作簡單,而且僅需要較少的監護,因此通常用於區域網高可靠性的分散系統中client/server應用程式。例如視頻會議系統,並不要求音頻視頻數據絕對的正確,只要保證連貫性就可以了,這種情況下顯然使用UDP會更合理一些。


三,基於Socket的java網路編程

1,什麼是Socket

  網路上的兩個程式通過一個雙向的通訊連接實現數據的交換,這個雙向鏈路的一端稱為一個Socket。Socket通常用來實現客戶方和服務方的連接。Socket是TCP/IP協議的一個十分流行的編程界面,一個Socket由一個IP地址和一個埠號唯一確定。但是,Socket所支持的協議種類也不光TCP/IP一種,因此兩者之間是沒有必然聯繫的。在Java環境下,Socket編程主要是指基於TCP/IP協議的網路編程。

2,Socket通訊的過程

  Server端Listen(監聽)某個埠是否有連接請求,Client端向Server 端發出Connect(連接)請求,Server端向Client端發回Accept(接受)消息。一個連接就建立起來了。Server端和Client 端都可以通過Send,Write等方法與對方通信。

  對於一個功能齊全的Socket,都要包含以下基本結構,其工作過程包含以下四個基本的步驟:

  (1)創建Socket;

  (2)打開連接到Socket的輸入/出流;

  (3)按照一定的協議對Socket進行讀/寫操作;

  (4)關閉Socket.(在實際應用中,並未使用到顯示的close,雖然很多文章都推薦如此,不過在我的程式中,可能因為程式本身比較簡單,要求不高,所以並未造成什麼影響。)

3,創建Socket

創建Socket

java在包java.net中提供了兩個類Socket和ServerSocket,分別用來表示雙向連接的客戶端和服務端。這是兩個封裝得非常好的類,使用很方便。其構造方法如下:

Socket(InetAddress address, int port);

Socket(InetAddress address, int port, boolean stream);

Socket(String host, int prot);

Socket(String host, int prot, boolean stream);

Socket(SocketImpl impl)

Socket(String host, int port, InetAddress localAddr, int localPort)

Socket(InetAddress address, int port, InetAddress localAddr, int localPort)

ServerSocket(int port);

ServerSocket(int port, int backlog);

ServerSocket(int port, int backlog, InetAddress bindAddr)

  其中address、host和port分別是雙向連接中另一方的IP地址、主機名和埠號,stream指明socket是流socket還是數據報socket,localPort表示本地主機的埠號,localAddr和 bindAddr是本地機器的地址(ServerSocket的主機地址),impl是socket的父類,既可以用來創建serverSocket又可以用來創建Socket。count則表示服務端所能支持的最大連接數。例如:學習視頻網 http://www.xxspw.com

Socket client = new Socket("127.0.01.", 80);

ServerSocket server = new ServerSocket(80);

  註意,在選擇埠時,必須小心。每一個埠提供一種特定的服務,只有給出正確的埠,才能獲得相應的服務。0~1023的埠號為系統所保留,例如http服務的埠號為80,telnet服務的埠號為21,ftp服務的埠號為23, 所以我們在選擇埠號時,最好選擇一個大於1023的數以防止發生衝突。

  在創建socket時如果發生錯誤,將產生IOException,在程式中必須對之作出處理。所以在創建Socket或ServerSocket是必須捕獲或拋出例外。

4,簡單的Client/Server程式

1. 客戶端程式

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

public class TalkClient {

    public static void main(String args[]) {

        try {

            Socket socket=new Socket("127.0.0.1",4700);

            //向本機的4700埠發出客戶請求

            BufferedReader sin=new BufferedReader(new InputStreamReader(System.in));

            //由系統標準輸入設備構造BufferedReader對象

            PrintWriter os=new PrintWriter(socket.getOutputStream());

            //由Socket對象得到輸出流,並構造PrintWriter對象

            BufferedReader is=new BufferedReader(new InputStreamReader(socket.getInputStream()));

            //由Socket對象得到輸入流,並構造相應的BufferedReader對象

            String readline;

            readline=sin.readLine(); //從系統標準輸入讀入一字元串

            while(!readline.equals("bye")){

                //若從標準輸入讀入的字元串為 "bye"則停止迴圈

                os.println(readline);

                //將從系統標準輸入讀入的字元串輸出到Server

                os.flush();

                //刷新輸出流,使Server馬上收到該字元串

                System.out.println("Client:"+readline);

                //在系統標準輸出上列印讀入的字元串

                System.out.println("Server:"+is.readLine());

                //從Server讀入一字元串,並列印到標準輸出上

                readline=sin.readLine(); //從系統標準輸入讀入一字元串

            } //繼續迴圈

            os.close(); //關閉Socket輸出流

            is.close(); //關閉Socket輸入流

            socket.close(); //關閉Socket

        } catch(Exception e) {

            System.out.println("Error"+e); //出錯,則列印出錯信息

        }

    }

}

 

 

2. 伺服器端程式

import java.io.*;
import java.net.*;
import java.applet.Applet;

public class TalkServer {

    public static void main(String args[]) {

        try {

            ServerSocket server=null;

            try {

                server=new ServerSocket(4700);

                //創建一個ServerSocket在埠4700監聽客戶請求

            } catch(Exception e) {

                System.out.println("can not listen to:"+e);

                //出錯,列印出錯信息

            }

            Socket socket=null;

            try {

                socket=server.accept();

                //使用accept()阻塞等待客戶請求,有客戶

                //請求到來則產生一個Socket對象,並繼續執行

            } catch(Exception e) {

                System.out.println("Error."+e);

                //出錯,列印出錯信息

            }

        String line;

        BufferedReader is=new BufferedReader(new InputStreamReader(socket.getInputStream()));

        //由Socket對象得到輸入流,並構造相應的BufferedReader對象

        PrintWriter os=newPrintWriter(socket.getOutputStream());

        //由Socket對象得到輸出流,並構造PrintWriter對象

        BufferedReader sin=new BufferedReader(new InputStreamReader(System.in));

        //由系統標準輸入設備構造BufferedReader對象

        System.out.println("Client:"+is.readLine());

        //在標準輸出上列印從客戶端讀入的字元串

        line=sin.readLine();

        //從標準輸入讀入一字元串

        while(!line.equals("bye")) {

            //如果該字元串為 "bye",則停止迴圈

            os.println(line);

            //向客戶端輸出該字元串

            os.flush();

            //刷新輸出流,使Client馬上收到該字元串

            System.out.println("Server:"+line);

            //在系統標準輸出上列印讀入的字元串

            System.out.println("Client:"+is.readLine());

            //從Client讀入一字元串,並列印到標準輸出上

            line=sin.readLine();

            //從系統標準輸入讀入一字元串

        } //繼續迴圈

        os.close(); //關閉Socket輸出流

        is.close(); //關閉Socket輸入流

        socket.close(); //關閉Socket

        server.close(); //關閉ServerSocket

        } catch(Exception e) {

            System.out.println("Error:"+e);

            //出錯,列印出錯信息

        }

    }

}

 

 

5,支持多客戶的client/server程式

  前面的Client/Server程式只能實現Server和一個客戶的對話。在實際應用中,往往是在伺服器上運行一個永久的程式,它可以接收來自其他多個客戶端的請求,提供相應的服務。為了實現在伺服器方給多個客戶提供服務的功能,需要對上面的程式進行改造,利用多線程實現多客戶機制。伺服器總是在指定的埠上監聽是否有客戶請求,一旦監聽到客戶請求,伺服器就會啟動一個專門的服務線程來響應該客戶的請求,而伺服器本身在啟動完線程之後馬上又進入監聽狀態,等待下一個客戶的到來。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 用eclipse創建一個WebService應用非常方便,步驟如下: 1.安裝WebService插件。www.eclipse.org網站上有下載,我下載的是wtp-all-in-one-sdk-R-1.5.4-win32,裡面就包括了。(我下載了好像沒什麼用,估計就跟之前安裝的Eclipse是同一
  • C介面與設計,需要註意的流程還是比較多的. 從演算法設計到演算法測試,到基礎庫封裝, 到基礎庫測試,後面是投入生產, 和框架融合再測試. 等等,都特別的耗時間, 今天分享的 是一個關於二叉樹基庫的封裝測試.下一個版本投入到生產環節.
  • 用單引號代替雙引號來包含字元串,這樣做會更快一些。因為PHP會在雙引號包圍的字元串中搜尋變數,單引號則不會,註意:只有echo能這麼做,它是一種可以把多個字元串當作參數的“函數”(譯註:PHP手冊中說echo是語言結構,不是真正的函數,故把函數加上了雙引號)。 1、如果能將類的方法定義成static
  • python中的range函數表示一個連續的有序序列,range使用起來很方便,因為在定義時就隱含了初始化過程,因為只需要給begin()和end()或者僅僅一個end(),就能表示一個連續的序列。還可以指定序列產生的步長,如range(0,10,8)產生的序列為[0, 8], 預設的步長為1,ra
  • 查詢資料有以下兩種方法: 1、 <#if appMap?exists> <#list appMap?keys as key> key:${key} value:${appMap.get(key)} </#list> </#if> 2、 <#list testMap.keySet() as testK
  • C++學習計劃 一、課程概況 1.課程名稱:c++遠征攻略 2.授課人姓名:james_yuan 3.課程鏈接地址: 二、課程列表 1.全部的課程 由於我有了一些c語言的基礎,所以我跳過了遠征前準備的課程直接進入了遠征起航的課程。 2.遠征起航的課程 這部分有兩部分: 第一部分的課程: 第二部分的課
  • java中記憶體的分配方式有兩種,一種是在堆中分配,一種是在堆棧中分配,所有new出來的對象都是在堆中分配的,函數中參數的傳遞是在棧中分配的。通常情況下堆的記憶體可以很大,比如32位操作系統中的虛擬記憶體都可以被堆所使用(當記憶體緊張的時候甚至硬碟都可以是堆的存儲空間),而堆棧的記憶體分配是有限的。 這和c+
  • Description: 求1!+2!+3!+4!+...+n!的結果。 Input: 輸入數據含有不多於50個的正整數n(1≤n≤12)。 Output: 對於每個n,輸出計算結果。每個計算結果應占獨立一行。 Sample Input: 3 6 Sample Output: 9 873 #incl
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...