Java使用線程池實(shí)現(xiàn)socket編程的方法詳解
前言
以多個(gè)客戶端和一個(gè)服務(wù)端的socket通信為例,服務(wù)端啟動(dòng)時(shí)創(chuàng)建一個(gè)固定大小的線程池。服務(wù)端每接收到一個(gè)連接請(qǐng)求后(通信任務(wù)),交給線程池執(zhí)行,任務(wù)類實(shí)現(xiàn)了Runnable接口,用于跟客戶端進(jìn)行讀寫操作,該類的對(duì)象作為任務(wù)通過(guò)execute(Runnable task)提交給線程池。
一、一個(gè)簡(jiǎn)單的C/S模型實(shí)現(xiàn)
1.服務(wù)器:
import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket; public class Server { public static void main(String[] args) throws Exception { System.out.println("server start"); ServerSocket server = new ServerSocket(1003); while (true) { Socket client = server.accept(); InputStream input = client.getInputStream(); byte[] b = new byte[8196]; int len = input.read(b); System.out.println(new String(b, 0, len)); if(new String(b).equals("close")) break; client.close(); } server.close(); } }
2.客戶端:
import java.io.OutputStream; import java.net.Socket; import java.util.Scanner; public class Client { public static void main(String[] args) throws Exception { System.out.println("client start"); Scanner scanner =new Scanner(System.in); Socket client =new Socket("localhost",1003); OutputStream out = client.getOutputStream(); while (true) { String str = scanner.nextLine(); out.write(str.getBytes()); } } }
此處只能服務(wù)器接收客戶端信息。
二、線程池使用方法
1.新建一個(gè)線程池
ExecutorService pool = Executors.newFixedThreadPool(3);
創(chuàng)建一個(gè)線程池,該線程池重用在共享無(wú)界隊(duì)列上運(yùn)行的固定數(shù)量的線程。 在任何時(shí)候,最多3個(gè)線程將是活動(dòng)的處理任務(wù)。如果在所有線程都處于活動(dòng)狀態(tài)時(shí)提交了其他任務(wù),它們將在隊(duì)列中等待,直到有線程可用。 如果任何線程在關(guān)閉之前的執(zhí)行過(guò)程中由于失敗而終止,如果需要執(zhí)行后續(xù)任務(wù),新的線程將取代它。 池中的線程將一直存在,直到顯式關(guān)閉。
2.用Runnable接口實(shí)現(xiàn)線程
private static class InnerThread implements Runnable{ public void run(); }
3.創(chuàng)建線程對(duì)象并提交至線程池執(zhí)行
InnerThread innerThread = new InnerThread(); pool.execute(innerThread);
三、結(jié)合起來(lái)
當(dāng)新的連接建立時(shí)創(chuàng)建一個(gè)新線程并提交到線程池
while(true){ Socket clientSocket = server.accept(); InnerThread innerThread = new InnerThread(clientSocket); pool.execute(innerThread); }
run方法為如何處理新連接,以及客戶端和服務(wù)端的信息交流。
四、使用新的輸入輸出流
由于OutputStream和InputStream類有方法沒(méi)有實(shí)現(xiàn)或是實(shí)現(xiàn)的不是很好,所以我們選擇使用
BufferedReader,PrintWriter類來(lái)實(shí)現(xiàn)通信。
服務(wù)器:
BufferedReader br = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); PrintWriter pw = new PrintWriter(new OutputStreamWriter(clientSocket.getOutputStream())); while(true){ String buf = br.readLine(); System.out.println(Thread.currentThread().getName()+" client: " + buf); if(buf.equals("close")){ break; } pw.println("response:"+buf); pw.flush(); } System.out.println("close client"); br.close(); pw.close(); clientSocket.close();
客戶端:
BufferedReader br = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); PrintWriter pw = new PrintWriter(new OutputStreamWriter(clientSocket.getOutputStream())); while(true){ System.out.print("client: "); String buf = sc.nextLine(); pw.println(buf); pw.flush(); if(buf.equals("close")){ break; } buf= br.readLine(); System.out.println("server: " + buf); if(buf.equals("close")){ break; } } br.close(); pw.close(); sc.close(); clientSocket.close();
這樣子就能較為方便的實(shí)現(xiàn)服務(wù)端向客戶端發(fā)送信息。
總結(jié)
以上就是今天要講的內(nèi)容,本文實(shí)現(xiàn)了使用線程池實(shí)現(xiàn)socket編程。
本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
解決springboot報(bào)錯(cuò)Could not resolve placeholder‘x
這篇文章主要介紹了解決springboot報(bào)錯(cuò):Could not resolve placeholder ‘xxx‘ in value “${XXXX}問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-11-11SpringBoot2.1.3修改tomcat參數(shù)支持請(qǐng)求特殊符號(hào)問(wèn)題
最近遇到一個(gè)問(wèn)題,比如GET請(qǐng)求中,key,value中帶有特殊符號(hào),請(qǐng)求會(huì)報(bào)錯(cuò)。接下來(lái)通過(guò)本文給大家分享解決SpringBoot2.1.3修改tomcat參數(shù)支持請(qǐng)求特殊符號(hào) ,需要的朋友可以參考下2019-05-05SpringBoot多種環(huán)境自由切換的實(shí)現(xiàn)
本文主要介紹了SpringBoot多種環(huán)境自由切換的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-08-08IntelliJ Idea SpringBoot 數(shù)據(jù)庫(kù)增刪改查實(shí)例詳解
SpringBoot 是 SpringMVC 的升級(jí),對(duì)于編碼、配置、部署和監(jiān)控,更加簡(jiǎn)單。這篇文章主要介紹了IntelliJ Idea SpringBoot 數(shù)據(jù)庫(kù)增刪改查實(shí)例,需要的朋友可以參考下2018-02-02springboot如何靜態(tài)加載@configurationProperties
這篇文章主要介紹了springboot如何靜態(tài)加載@configurationProperties,本文一個(gè)錯(cuò)誤案例和成功案例結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-07-07springboot部署linux訪問(wèn)服務(wù)器資源的方法
這篇文章主要介紹了springboot部署linux訪問(wèn)服務(wù)器資源,部署springboot項(xiàng)目至服務(wù)器用了幾種不同方法,文中給大家詳細(xì)介紹,需要的朋友可以參考下2019-12-12SpringBoot ThreadLocal 簡(jiǎn)單介紹及使用詳解
ThreadLocal 叫做線程變量,意思是 ThreadLocal 中填充的變量屬于當(dāng)前線程,該變量對(duì)其他線程而言是隔離的,也就是說(shuō)該變量是當(dāng)前線程獨(dú)有的變量,這篇文章主要介紹了SpringBoot ThreadLocal 的詳解,需要的朋友可以參考下2024-01-01Spring-retry實(shí)現(xiàn)循環(huán)重試功能
這篇文章主要介紹了Spring-retry 優(yōu)雅的實(shí)現(xiàn)循環(huán)重試功能,通過(guò)@Retryable注解,優(yōu)雅的實(shí)現(xiàn)循環(huán)重試功能,需要的朋友可以參考下2023-07-07