Socket和ServerSocket

對于即時類應用或者即時類的游戲,HTTP協議很多時候無法滿足于我們的需求。這會,Socket對于我們來說就非常實用了。下面是本次學習的筆記。主要分異常類型、交互原理、Socket、ServerSocket、多線程這幾個方面闡述。


?


異常類型
在了解Socket的內容之前,先要了解一下涉及到的一些異常類型。以下四種類型都是繼承于IOException,所以很多之后直接彈出IOException即可。
UnkownHostException: ? ?  主機名字或IP錯誤
ConnectException: ? ?    服務器拒絕連接、服務器沒有啟動、(超出隊列數,拒絕連接)
SocketTimeoutException: ? ? ?連接超時
BindException: ? ?      Socket對象無法與制定的本地IP地址或端口綁定
?
交互過程


Socket與ServerSocket的交互,下面的圖片我覺得已經說的很詳細很清楚了。


?
Socket
構造函數
Socket()


Socket(InetAddress address, int port)throws UnknownHostException, IOException
Socket(InetAddress address, int port, InetAddress localAddress, int localPort)throws IOException
Socket(String host, int port)throws UnknownHostException, IOException
Socket(String host, int port, InetAddress localAddress, int localPort)throws IOException
?
除去第一種不帶參數的之外,其它構造函數會嘗試建立與服務器的連接。如果失敗會拋出IOException錯誤。如果成功,則返回Socket對象。
InetAddress是一個用于記錄主機的類,其靜態getHostByName(String msg)可以返回一個實例,其靜態方法getLocalHost()也可以獲得當前主機的IP地址,并返回一個實例。Socket(String host, int port, InetAddress localAddress, int localPort)構造函數的參數分別為目標IP、目標端口、綁定本地IP、綁定本地端口。
?
Socket方法
getInetAddress(); ? ?  遠程服務端的IP地址
getPort(); ? ?      遠程服務端的端口
getLocalAddress() ? ?  本地客戶端的IP地址
getLocalPort() ? ?    本地客戶端的端口
getInputStream(); ? ? 獲得輸入流
getOutStream(); ? ?  獲得輸出流
值得注意的是,在這些方法里面,最重要的就是getInputStream()和getOutputStream()了。
?
Socket狀態
isClosed(); ? ? ? ?    //連接是否已關閉,若關閉,返回true;否則返回false
isConnect();      //如果曾經連接過,返回true;否則返回false
isBound(); ? ? ? ?    //如果Socket已經與本地一個端口綁定,返回true;否則返回false
如果要確認Socket的狀態是否處于連接中,下面語句是很好的判斷方式。
boolean isConnection=socket.isConnected() && !socket.isClosed(); ? //判斷當前是否處于連接
?


半關閉Socket
很多時候,我們并不知道在獲得的輸入流里面到底讀多長才結束。下面是一些比較普遍的方法:
自定義標識符(譬如下面的例子,當受到“bye”字符串的時候,關閉Socket)
告知讀取長度(有些自定義協議的,固定前幾個字節表示讀取的長度的)
讀完所有數據
當Socket調用close的時候關閉的時候,關閉其輸入輸出流
?
ServerSocket
構造函數
ServerSocket()throws IOException
ServerSocket(int port)throws IOException
ServerSocket(int port, int backlog)throws IOException
ServerSocket(int port, int backlog, InetAddress bindAddr)throws IOException
?
注意點:
1. port服務端要監聽的端口;backlog客戶端連接請求的隊列長度;bindAddr服務端綁定IP
2. 如果端口被占用或者沒有權限使用某些端口會拋出BindException錯誤。譬如1~1023的端口需要管理員才擁有權限綁定。
3. 如果設置端口為0,則系統會自動為其分配一個端口;
4. bindAddr用于綁定服務器IP,為什么會有這樣的設置呢,譬如有些機器有多個網卡。
5. ServerSocket一旦綁定了監聽端口,就無法更改。ServerSocket()可以實現在綁定端口前設置其他的參數。
?
單線程的ServerSocket例子
復制代碼
public void service(){
? ? while(true){
? ? ? ? Socket socket=null;
? ? ? ? try{
? ? ? ? ? ? socket=serverSocket.accept();//從連接隊列中取出一個連接,如果沒有則等待
? ? ? ? ? ? System.out.println("新增連接:"+socket.getInetAddress()+":"+socket.getPort());
? ? ? ? ? ? ...//接收和發送數據
? ? ? ? }catch(IOException e){e.printStackTrace();}finally{
? ? ? ? ? ? try{
? ? ? ? ? ? ? ? if(socket!=null) socket.close();//與一個客戶端通信結束后,要關閉Socket
? ? ? ? ? ? }catch(IOException e){e.printStackTrace();}
? ? ? ? }
? ? }
}
復制代碼
?


多線程的ServerSocket
多線程的好處不用多說,而且大多數的場景都是多線程的,無論是我們的即時類游戲還是IM,多線程的需求都是必須的。下面說說實現方式:
主線程會循環執行ServerSocket.accept();
當拿到客戶端連接請求的時候,就會將Socket對象傳遞給多線程,讓多線程去執行具體的操作;
實現多線程的方法要么繼承Thread類,要么實現Runnable接口。當然也可以使用線程池,但實現的本質都是差不多的。
?
這里舉例:
下面代碼為服務器的主線程。為每個客戶分配一個工作線程:
復制代碼
public void service(){
? ? while(true){
? ? ? ? Socket socket=null;
? ? ? ? try{
? ? ? ? ? ? socket=serverSocket.accept(); ? ? ? ? ? ? ? ? ? ? ? ?//主線程獲取客戶端連接
? ? ? ? ? ? Thread workThread=new Thread(new Handler(socket)); ? ?//創建線程
? ? ? ? ? ? workThread.start(); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?//啟動線程
? ? ? ? }catch(Exception e){
? ? ? ? ? ? e.printStackTrace();
? ? ? ? }
? ? }
}
復制代碼
?


當然這里的重點在于如何實現Handler這個類。Handler需要實現Runnable接口:
復制代碼
class Handler implements Runnable{
? ? private Socket socket;
? ? public Handler(Socket socket){
? ? ? ? this.socket=socket;
? ? }
? ??
? ? public void run(){
? ? ? ? try{
? ? ? ? ? ? System.out.println("新連接:"+socket.getInetAddress()+":"+socket.getPort());
? ? ? ? ? ? Thread.sleep(10000);
? ? ? ? }catch(Exception e){e.printStackTrace();}finally{
? ? ? ? ? ? try{
? ? ? ? ? ? ? ? System.out.println("關閉連接:"+socket.getInetAddress()+":"+socket.getPort());
? ? ? ? ? ? ? ? if(socket!=null)socket.close();
? ? ? ? ? ? }catch(IOException e){
? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? }
? ? ? ? }
? ? }
}
復制代碼
當然是先多線程還有其它的方式,譬如線程池,或者JVM自帶的線程池都可以。這里就不說明了。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/451979.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/451979.shtml
英文地址,請注明出處:http://en.pswp.cn/news/451979.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

徹底搞清楚Android中的 Attr

版權聲明:本文為sydMobile原創文章,轉載請務必注明出處! https://blog.csdn.net/sydMobile/article/details/79978187 相信這個詞對于Android開發者來說十分熟悉了,那么你對他到底有多了解呢? 回憶起我剛開始接觸Andr…

D. Relatively Prime Graph

Lets call an undirected graph G(V,E)G(V,E) relatively prime if and only if for each edge (v,u)∈E(v,u)∈E GCD(v,u)1GCD(v,u)1 (the greatest common divisor of vv and uu is 11). If there is no edge between some pair of vertices vv and uu then the value of GC…

解決 : org.apache.ibatis.binding.BindingException: Invalid bound statement (not found)

前些天發現了一個巨牛的人工智能學習網站,通俗易懂,風趣幽默,忍不住分享一下給大家。點擊跳轉到教程。 報錯: org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.tanj.mapper.SendDeta…

網絡爬蟲--19.【Scrapy-Redis實戰】分布式爬蟲爬取房天下--環境準備

文章目錄0. 思路一. 虛擬機Ubuntu0中安裝Redis二. 虛擬機Ubuntu1中安裝Redis三. Windows服務器上安裝Redis四. 安裝cmder五. 安裝RedisDesktopManager六. 修改Windows中的配置文件redis.windows.conf七. Ubuntu連接Windows上 的Redis服務器-----------------------------------…

開發人員,請愛護你的身體

最近一周身體極度不適,口腔潰瘍、嗓子痛、感冒咳嗽、發燒,統統來了一個遍,非常痛苦。所以最近一直關注有關于軟件開發人員的身體健康問題的網站、文章。 看了許多文章,在結合自己在這一周之內痛苦的感受,所以才寫這樣…

tkinter中scale拖拉改變值控件(十一)

scale拖拉改變值控件 使用戶通過拖拽改變值 簡單的實現: 1 import tkinter2 3 wuya tkinter.Tk() 4 wuya.title("wuya") 5 wuya.geometry("300x2001020") 6 7 8 # 創建對象 9 scale1 tkinter.Scale(wuya, from_0, to100) 10 scale1.pac…

vue+elementUI開發實踐問題總結

最近公司項目采用vue,實行前后端分離開發,采用element-ui框架,對于項目中遇到的問題進行記錄,便于日后查詢。 vueelementui怎樣點擊table中的單元格觸發事件?官方文檔是采用的cell-click方式。實際項目中需要在不同的t…

Socket的getInputStream()方法

Socket的getInputStream()方法可以獲得網絡連接輸入,同時返回一個InputStream實例 。

計算機圖形學理論(4):緩沖區

本系列根據國外一個圖形小哥的講解為本,整合互聯網的一些資料,結合自己的一些理解。 什么是緩沖區? 緩沖區是保存某些數據的臨時存儲空間。 為什么我們需要緩沖區?原因很簡單,當數據量很大時,因為計算機無…

解決:Every derived table must have its own alias

前些天發現了一個巨牛的人工智能學習網站,通俗易懂,風趣幽默,忍不住分享一下給大家。點擊跳轉到教程。 報錯: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Every derived table must have its own alias 解決&…

網絡爬蟲--20.【Scrapy-Redis實戰】分布式爬蟲獲取房天下--代碼實現

文章目錄一. 案例介紹二.創建項目三. settings.py配置四. 詳細代碼五. 部署1. windows環境下生成requirements.txt文件2. xshell連接ubuntu服務器并安裝依賴環境3. 修改部分代碼4. 上傳代碼至服務器并運行一. 案例介紹 爬取房天下(https://www1.fang.com/&#xff…

同一臺電腦安裝python2python3

【安裝之前,先了解一下概念】 python是什么? Python是一種面向對象的解釋型計算機程序設計語言,由荷蘭人Guido van Rossum于1989年發明,第一個公開發行版發行于1991年。 Python是純粹的自由軟件, 源代碼和解釋器CPytho…

程序員的常見健康問題

其實這些問題不僅見于程序員,其他長期經常坐在電腦前的職場人士(比如:網絡編輯、站長等),都會有其中的某些健康問題。希望從事這些行業的朋友,對自己的健康問題,予以重視。以下是全文。 我最近…

Java中BufferedReader和InputStreamReader

BufferedReader 類BufferedReader 由Reader類擴展而來,提供通用的緩沖方式文本讀取,而且提供了很實用的readLine,讀取一個文本行,從字符輸入流中讀取文本,緩沖各個字符,從而提供字符、數組和行的高效讀取。…

網絡爬蟲--21.Scrapy知識點總結

文章目錄一. Scrapy簡介二. Scrapy架構圖三. Scrapy框架模塊功能四. 安裝和文檔五. 創建項目六. 創建爬蟲一. Scrapy簡介 二. Scrapy架構圖 三. Scrapy框架模塊功能 四. 安裝和文檔 中文文檔:https://scrapy-chs.readthedocs.io/zh_CN/latest/intro/tutorial.html …

Spring 定時任務的幾種實現

前些天發現了一個巨牛的人工智能學習網站,通俗易懂,風趣幽默,忍不住分享一下給大家。點擊跳轉到教程。 近日項目開發中需要執行一些定時任務,比如需要在每天凌晨時候,分析一次前一天的日志信息,借此機會整…

trie樹(字典樹)

trie樹學習 學習trie樹 轉載于:https://www.cnblogs.com/cjoierljl/p/9317023.html

Vue 教程第四篇—— Vue 實例化時基本屬性

實例元素 el 實例元素指的是 Vue 實例化時編譯的容器元素&#xff0c;或者說是 Vue 作用的元素容器 <div id"app"></div> var vm new Vue({el: #app}) 也可以為實例元素指定其它選擇器 <div class"app"></div> var vm new Vue({…

Ubuntu將在明年推出平板及手機系統

4月26日下午消息&#xff0c;知名Linux廠商Canonical今天正式發布Ubuntu 12.04版開源操作系統。Ubuntu中國首席代表于立強透露&#xff0c;針對平板電腦的Ubuntu操作系統將在明年推出。 Ubuntu 12.04版開源操作系統發布 Ubuntu操作系統是一款開源操作系統&#xff0c;主要與OE…