java API爲咱們網絡通訊提供了服務器套接字ServerSocket類和客戶端套接字Socket,Socket是網絡驅動層提供給應用程序編程的接口和一種機制。
下面提供具體實現例子
服務端--ServerSocket
ServerSocket類實現了服務器的套接字,主要方法
ServerSocket(int port)-----建立綁定到特定端口的服務器套接字
void setSoTimeout(timeout);----指定超時時間
InetAdress getInetAddress()----返回此服務器套接字的本機地址
Socket accept()--------------偵聽並接受此套接字的鏈接
示例代碼:
- package com;
-
- import java.io.BufferedInputStream;
- import java.io.BufferedOutputStream;
- import java.io.IOException;
- import java.net.ServerSocket;
- import java.net.Socket;
-
-
- public class Test {
-
- public static void main(String[] args) {
-
- try {
- ServerSocket server=new ServerSocket(8080);
- //等待客戶端鏈接
- while(true){
- Socket client=server.accept();
- //每一個客戶端創建一個線程
- new Thread(new myRunnable(client)).start();;
- }
-
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- }
-
- }
-
- class myRunnable implements Runnable{
-
- private Socket socket;
-
- public myRunnable(Socket s)
- {
- this.socket=s;
- }
- //----run方法運行完畢,線程正常結束
- @Override
- public void run() {
-
- try {
- //接收客戶端數據
- BufferedInputStream is=new BufferedInputStream(socket.getInputStream());
- int data=is.read()+1;//把客戶的數據加一
-
- Thread.sleep(1000);//休眠一秒
- //輸出到客戶端
- BufferedOutputStream os=new BufferedOutputStream(socket.getOutputStream());
- os.write(data);//返回數據給客戶端
-
- os.close();
- os.close();
-
- } catch (IOException | InterruptedException e) {
- e.printStackTrace();
- }
-
-
- }
-
- }
複製代碼
客戶端----Socket
Socket類實現客戶端套接字,套接字是兩臺機器間通訊的端點,主要方法有
Socket(String host,int port)----建立一個套接字將其鏈接到指定主機的指定端口號
InputStream getInputStream()----返回此套接字的輸入流
OutputStream getOutputStream()----返回此套接字的輸出流
示例代碼:
- package com;
-
- import java.io.BufferedInputStream;
- import java.io.BufferedOutputStream;
- import java.io.IOException;
- import java.net.Socket;
- import java.net.UnknownHostException;
-
- public class Client {
-
- public static void main(String[] args) {
-
- for(int i=0;i<20;i++)
- {
-
- try {
- Socket socket = new Socket("localhost", 8080);
- //輸出到服務器
- BufferedOutputStream os=new BufferedOutputStream(socket.getOutputStream());
- os.write(i);
- os.flush();
- //os.close();不能再這裏關閉流,關閉流會致使socket也關閉
-
- // 構建字符緩衝流
- BufferedInputStream is=new BufferedInputStream(socket.getInputStream());
-
- int data=is.read();
- is.close();
-
- os.close();
-
- System.out.println(data);
- } catch (UnknownHostException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
- }
-
- }
複製代碼
主要不能提早關閉輸入輸出流,關閉輸入輸出流會致使Socket關閉
能夠引發網絡鏈接關閉的狀況有如下4種:
1.直接調用Socket類的close方法。
2.只要Socket類的InputStream和OutputStream有一個關閉,網絡鏈接自動關閉(必須經過調用InputStream和OutputStream的 close方法關閉流,才能使網絡可愛接自動關閉)。
3.在程序退出時網絡鏈接自動關閉。
4.將Socket對象設爲null或未關閉最使用new Socket(…)創建新對象後,由JVM的垃圾回收器回收爲Socket對象分配的內存空間後自動關閉網絡鏈接。
線程池
在處理多個客戶端時是爲每個鏈接建立一個線程,然而頻繁的線程建立會影響性能,因此咱們可使用線程池來解決頻線程的建立問題。
線程池:線程池是一種預先建立線程的一種技術。線程池在任務還沒到來以前,建立必定數量的線程,放到空閒隊列,而後對這些資源進行復用,減小頻繁的線程建立和銷燬。
JDK1.5版本後提供了線程池,線程池的頂級接口是Executor,是一個執行工具,線程池的直接接口是ExecutorService,是併發開發中經常使用的工具類
要配置一個線程池是比較複雜的,尤爲是對於線程池的原理不是很清楚的狀況下,頗有可能配置的線程池不是較優的,所以在Executors類裏面提供了一些靜態工廠,生成一些經常使用的線程池。
1. newSingleThreadExecutor
建立一個單線程的線程池。這個線程池只有一個線程在工做,也就是至關於單線程串行執行全部任務。若是這個惟一的線程由於異常結束,那麼會有一個新的線程來替代它。此線程池保證全部任務的執行順序按照任務的提交順序執行。
2. newFixedThreadPool
建立固定大小的線程池。每次提交一個任務就建立一個線程,直到線程達到線程池的最大大小。線程池的大小一旦達到最大值就會保持不變,若是某個線程由於執行異常而結束,那麼線程池會補充一個新線程。
3. newCachedThreadPool
建立一個可緩存的線程池。若是線程池的大小超過了處理任務所須要的線程,
那麼就會回收部分空閒(60秒不執行任務)的線程,當任務數增長時,此線程池又能夠智能的添加新線程來處理任務。此線程池不會對線程池大小作限制,線程池大小徹底依賴於操做系統(或者說JVM)可以建立的最大線程大小。
4. newScheduledThreadPool
建立一個大小無限的線程池。此線程池支持定時以及週期性執行任務的需求。
此時咱們在服務器的用上線程池,使用newFixedThreadPool,代碼改成
Java代碼 [url=][/url]
- package com;
-
- import java.io.BufferedInputStream;
- import java.io.BufferedOutputStream;
- import java.io.IOException;
- import java.net.ServerSocket;
- import java.net.Socket;
-
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
-
-
- public class Test {
-
- public static void main(String[] args) {
-
- try {
- ServerSocket server=new ServerSocket(8080);
- //獲取cpu數
- int cpu_Num=Runtime.getRuntime().availableProcessors();
- //建立指定大小的線程池
- ExecutorService es=Executors.newFixedThreadPool(cpu_Num);
- //等待客戶端鏈接
- while(true){
- Socket client=server.accept();
- //每一個客戶端創建一個線程
- //new Thread(new myRunnable(client)).start();
- es.execute(new myRunnable(client));
- }
-
- } catch (IOException e) {
- e.printStackTrace();
- }
-
- }
-
- }
-
- class myRunnable implements Runnable{
-
- private Socket socket;
-
- public myRunnable(Socket s)
- {
- this.socket=s;
- }
- //----run方法運行完畢,線程正常結束
- @Override
- public void run() {
-
- try {
- //接收客戶端數據
- BufferedInputStream is=new BufferedInputStream(socket.getInputStream());
- int data=is.read()+1;//把客戶的數據加一
-
- Thread.sleep(1000);//休眠一秒
- //輸出到客戶端
- BufferedOutputStream os=new BufferedOutputStream(socket.getOutputStream());
- os.write(data);//返回數據給客戶端
-
- os.close();
- os.close();
-
- } catch (IOException | InterruptedException e) {
- e.printStackTrace();
- }
-
-
- }
-
- }
複製代碼
這樣雖然現實了併發服務器,但這樣的服務器效率低,吞吐量低,想提升服務器性能,能夠研究學習java的nio和aio,能大大提高服務器性能。
|