Java套接字Socket

什么是套接字Socket

Socket本身就是網(wǎng)絡(luò)上的兩個程序可以互相發(fā)送請求和接收請求耸弄,應(yīng)用程序可以利用套接字在網(wǎng)絡(luò)上進行數(shù)據(jù)傳輸。
Socket本身作為應(yīng)用程序和網(wǎng)絡(luò)層TCP/UDP之間的一個抽象層闺属,在TCP中主要采用流套接字,采用的方式就是點對點通過字節(jié)流傳輸怨咪;UDP主要采用數(shù)據(jù)報套接字屋剑。

面向連接的入門例子

功能:客戶端發(fā)送請求润匙,服務(wù)器接收請求
服務(wù)端:

public class MyServer {

    class HandleTask {
        
        private Socket socket;
        
        public HandleTask() {}

        public HandleTask(Socket socket) {
            this.socket = socket;
        }
        
        public void handle() {
            StringBuilder sb = new StringBuilder("Hello: ");
            InputStream is = null;
            BufferedReader br = null;
            
            try {
                is = socket.getInputStream();
                br = new BufferedReader(new InputStreamReader(is));
                sb.append(br.readLine());
                System.out.println(sb.toString());
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (null != br) {
                        br.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
                
                try {
                    if (null != is) {
                        is.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            
            try {
                Thread.sleep(15000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            
            System.out.println(sb.toString() + "-- 結(jié)束執(zhí)行 --");
        }
    }
    
    
    public static void main(String[] args) throws IOException{
        ServerSocket serverSocket = null;
        Socket socket = null;
        try {
            serverSocket = new ServerSocket(9999);
            while (true) {
                socket = serverSocket.accept();
                new MyServer().new HandleTask(socket).handle();
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (null != socket) {
                socket.close();
            }
            
            if (null != serverSocket) {
                serverSocket.close();
            }
        }
    }
}

思路:
① 服務(wù)器端啟動了ServerSocket诗眨,然后綁定了端口9999。
② 調(diào)用accept方法孕讳,阻塞等待客戶端連接匠楚。
③ 當(dāng)接收到客戶端的請求之后,通過字節(jié)流獲取客戶端發(fā)來的信息厂财。
多個客戶端:

public class MyClient {

    public static void main(String[] args) {
        Socket socket = null;
        BufferedWriter bw = null;
        Scanner scanner = new Scanner(System.in);
        
        try {
            socket = new Socket("localhost", 9999);
            bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            bw.write(scanner.nextLine());
            bw.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            scanner.close();
            
            try {
                if (null != bw) {
                    bw.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            
            try {
                if (null != socket) {
                    socket.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

public class MyClient2 {

    public static void main(String[] args) {
        Socket socket = null;
        BufferedWriter bw = null;
        Scanner scanner = new Scanner(System.in);
        
        try {
            socket = new Socket("localhost", 9999);
            bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            bw.write(scanner.nextLine());
            bw.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            scanner.close();
            
            try {
                if (null != bw) {
                    bw.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            
            try {
                if (null != socket) {
                    socket.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

結(jié)果:


1.jpg

解釋:
上面這個例子的缺陷就是如果是多個請求去等待服務(wù)器端去處理芋簿,那么服務(wù)器端會按照收到請求的順序執(zhí)行,這樣如果第一個請求執(zhí)行時間很長璃饱,那么第二個請求就很長時間等不到執(zhí)行与斤。

多線程執(zhí)行多個客戶端

場景
基于上面的例子,思考:服務(wù)器在很多情況下是需要接收來自很多個客戶端的請求的荚恶。
解決辦法
根據(jù)多線程時間分片方式來解決問題:多個客戶端的請求撩穿,那么服務(wù)器采用每次接收到一個請求就創(chuàng)建一個線程來執(zhí)行。
采用多線程改進的服務(wù)端

public class MyThreadServer {
    
    class HandleTask extends Thread{

        private Socket socket;
        public HandleTask() {}

        public HandleTask(Socket socket) {
            this.socket = socket;
        }
        
        @Override
        public void run() {
            StringBuilder sb = new StringBuilder("Hello: ");
            InputStream is = null;
            BufferedReader br = null;
            
            try {
                is = socket.getInputStream();
                br = new BufferedReader(new InputStreamReader(is));
                sb.append(br.readLine());
                System.out.println(sb.toString());
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (null != br) {
                        br.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
                
                try {
                    if (null != is) {
                        is.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            
            try {
                Thread.sleep(15000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            
            System.out.println(sb.toString() + "-- 結(jié)束執(zhí)行 --");
        }
    }
    
    public static void main(String[] args) {
        ServerSocket serverSocket = null;
        Socket socket = null;
        try {
            serverSocket = new ServerSocket(9999);
            while (true) {
                socket = serverSocket.accept();
                new MyThreadServer().new HandleTask(socket).start();
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            try {
                if (null != socket) {
                    socket.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            
            try {
                if (null != serverSocket) {
                    serverSocket.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
2.jpg

3.jpg

方案使用的模型:
上面的程序?qū)iT使用一個接收者線程來專門負責(zé)監(jiān)聽客戶端的請求谒撼,接收到客戶端的請求食寡,就為其創(chuàng)建一個新的線程去執(zhí)行業(yè)務(wù)處理,最后通過字節(jié)流進行返回響應(yīng)廓潜。這種模型就是BIO(阻塞IO)抵皱。
方案的缺點:
這種工作的模型有一個問題,就是當(dāng)請求數(shù)很多時辩蛋,就會創(chuàng)建和請求數(shù)一樣多匹配線程呻畸。最終當(dāng)并發(fā)量上來,那么系統(tǒng)的性能將會下降悼院。

線程池執(zhí)行多個客戶端

場景:
基于上面的例子擂错,使用多線程方式來處理請求,每個請求都創(chuàng)建一個匹配的線程樱蛤,浪費線程資源钮呀。采用線程池管理線程剑鞍,可以充分利用線程。
采用線程池改進的服務(wù)端:

public class MyThreadPoolServer {

    private static ExecutorService es = Executors.newCachedThreadPool();
    
    class HandleTask extends Thread {

        private Socket socket;
        public HandleTask() {}

        public HandleTask(Socket socket) {
            this.socket = socket;
        }
        
        @Override
        public void run() {
            StringBuilder sb = new StringBuilder("Hello: ");
            InputStream is = null;
            BufferedReader br = null;
            
            try {
                is = socket.getInputStream();
                br = new BufferedReader(new InputStreamReader(is));
                sb.append(br.readLine());
                System.out.println(sb.toString());
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (null != br) {
                        br.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
                
                try {
                    if (null != is) {
                        is.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            
            try {
                Thread.sleep(15000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            
            System.out.println(sb.toString() + "-- 結(jié)束執(zhí)行 --");
        }
    }
    
    public static void main(String[] args) {
        ServerSocket serverSocket = null;
        Socket socket = null;
        try {
            serverSocket = new ServerSocket(9999);
            while (true) {
                socket = serverSocket.accept();
                es.execute(new MyThreadServer().new HandleTask(socket));
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            try {
                if (null != socket) {
                    socket.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            
            try {
                if (null != serverSocket) {
                    serverSocket.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
4.jpg

方案使用的模型:


5.jpg
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末爽醋,一起剝皮案震驚了整個濱河市蚁署,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蚂四,老刑警劉巖光戈,帶你破解...
    沈念sama閱讀 219,270評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異遂赠,居然都是意外死亡久妆,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評論 3 395
  • 文/潘曉璐 我一進店門跷睦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來筷弦,“玉大人,你說我怎么就攤上這事抑诸±们伲” “怎么了?”我有些...
    開封第一講書人閱讀 165,630評論 0 356
  • 文/不壞的土叔 我叫張陵蜕乡,是天一觀的道長奸绷。 經(jīng)常有香客問我,道長层玲,這世上最難降的妖魔是什么号醉? 我笑而不...
    開封第一講書人閱讀 58,906評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮辛块,結(jié)果婚禮上畔派,老公的妹妹穿的比我還像新娘。我一直安慰自己憨降,他們只是感情好父虑,可當(dāng)我...
    茶點故事閱讀 67,928評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著授药,像睡著了一般士嚎。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上悔叽,一...
    開封第一講書人閱讀 51,718評論 1 305
  • 那天莱衩,我揣著相機與錄音,去河邊找鬼娇澎。 笑死笨蚁,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播括细,決...
    沈念sama閱讀 40,442評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼伪很,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了奋单?” 一聲冷哼從身側(cè)響起锉试,我...
    開封第一講書人閱讀 39,345評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎览濒,沒想到半個月后呆盖,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,802評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡贷笛,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,984評論 3 337
  • 正文 我和宋清朗相戀三年应又,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片乏苦。...
    茶點故事閱讀 40,117評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡株扛,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出邑贴,到底是詐尸還是另有隱情席里,我是刑警寧澤叔磷,帶...
    沈念sama閱讀 35,810評論 5 346
  • 正文 年R本政府宣布拢驾,位于F島的核電站,受9級特大地震影響改基,放射性物質(zhì)發(fā)生泄漏繁疤。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,462評論 3 331
  • 文/蒙蒙 一秕狰、第九天 我趴在偏房一處隱蔽的房頂上張望稠腊。 院中可真熱鬧,春花似錦鸣哀、人聲如沸架忌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽叹放。三九已至,卻和暖如春挠羔,著一層夾襖步出監(jiān)牢的瞬間井仰,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評論 1 272
  • 我被黑心中介騙來泰國打工破加, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留俱恶,地道東北人。 一個月前我還...
    沈念sama閱讀 48,377評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像合是,于是被迫代替她去往敵國和親了罪。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,060評論 2 355

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

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理聪全,服務(wù)發(fā)現(xiàn)捶惜,斷路器,智...
    卡卡羅2017閱讀 134,667評論 18 139
  • Java知識點1荔烧、==和equals的區(qū)別基本類型比較==比較內(nèi)容 equals比較地址值引用類型比較==比較地址...
    壓抑的內(nèi)心閱讀 592評論 0 0
  • 1.啟動Spark集群 2.執(zhí)行jar包 3.啟動了Driver進程(通過執(zhí)行代碼啟動了Driver) 然后生成了...
    0_9f3a閱讀 1,105評論 0 0
  • 不知道從什么時候開始鹤竭,我們聊天的字變得越來越少踊餐,代替文字的就是一些圖標(biāo)或是符號。比如臀稚,心情不好吝岭,用哭臉表示;需要...
    邊際小黑閱讀 151評論 0 1
  • 同事的女兒今年十八歲吧寺,小姑娘準(zhǔn)備以獻血的形式窜管,慶祝自己長大成人。00后的孩子們稚机,想法越來越不同凡響幕帆。 ...
    輕輕道來閱讀 159評論 0 1