Java使用多線程實現Socket多客戶端的通訊

 要想詳細瞭解socket,你們請自行百度,我這裏只簡單介紹。java

  在網絡中,咱們能夠利用ip地址+協議+端口號惟一標示網絡中的一個進程。而socket編程就是爲了完成兩個惟一進程之間的通訊(一個是客戶端,一個是服務器端),其中用到的協議是TCP/UDP協議,它們都屬於傳輸層的協議。編程

  TCP是基於鏈接的協議,在收發數據前,須要創建可靠的鏈接,也就是所謂的三次握手。使用TCP協議時,數據會準確到達,可是效率較低。服務器

  UDP是面向非鏈接的協議,它不與對方創建鏈接,而是直接就把數據包發送過去。使用UDP協議時,傳輸效率高,可是不能保證數據準確到達,視頻聊天,語音聊天時就用的UDP協議。網絡

  以使用TCP協議通信的socket爲例,其交互流程大概是這樣子的:socket

              服務器端              客戶端ide

           建立服務器端的socket        建立客戶端的socketthis

           綁定端口號             鏈接服務器端的端口編碼

           監聽端口              向服務器端發送數據.net

           接收客戶端的鏈接請求        關閉socket線程

           讀取客戶端發送數據

           關閉socket

 

  下面貼上代碼:

  服務器端:

package SocketStudy;

import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

public class SocketServer {
public static void main(String[] args) {
try {
ServerSocket serverSocket = new ServerSocket(10068);//建立綁定到特定端口的服務器Socket。
Socket socket = null;//須要接收的客戶端Socket
int count = 0;//記錄客戶端數量
System.out.println("服務器啓動");
//定義一個死循環,不停的接收客戶端鏈接
while (true) {
socket = serverSocket.accept();//偵聽並接受到此套接字的鏈接
InetAddress inetAddress=socket.getInetAddress();//獲取客戶端的鏈接
ServerThread thread=new ServerThread(socket,inetAddress);//本身建立的線程類
thread.start();//啓動線程
count++;//若是正確創建鏈接
System.out.println("客戶端數量:" + count);//打印客戶端數量
}
} catch (IOException e) {
e.printStackTrace();
}

}
}

 

 自定義線程類:

package SocketStudy;

import java.io.*;
import java.net.InetAddress;
import java.net.Socket;

public class ServerThread extends Thread {
Socket socket = null;
InetAddress inetAddress=null;//接收客戶端的鏈接

public ServerThread(Socket socket,InetAddress inetAddress) {
this.socket = socket;
this.inetAddress=inetAddress;
}

@Override
public void run() {
InputStream inputStream = null;//字節輸入流
InputStreamReader inputStreamReader = null;//將一個字節流中的字節解碼成字符
BufferedReader bufferedReader = null;//爲輸入流添加緩衝
OutputStream outputStream = null;//字節輸出流
OutputStreamWriter writer = null;//將寫入的字符編碼成字節後寫入一個字節流
try {
inputStream = socket.getInputStream();
inputStreamReader = new InputStreamReader(inputStream, "UTF-8");
bufferedReader = new BufferedReader(inputStreamReader);
String info = null;//臨時

//循環讀取客戶端信息
while ((info = bufferedReader.readLine()) != null) {
//獲取客戶端的ip地址及發送數據
System.out.println("服務器端接收:"+"{'from_client':'"+socket.getInetAddress().getHostAddress()+"','data':'"+info+"'}");
}

socket.shutdownInput();//關閉輸入流

//響應客戶端請求
outputStream = socket.getOutputStream();
writer = new OutputStreamWriter(outputStream, "UTF-8");
writer.write("{'to_client':'"+inetAddress.getHostAddress()+"','data':'我是服務器數據'}");
writer.flush();//清空緩衝區數據
} catch (IOException e) {
e.printStackTrace();
} finally {
//關閉資源
try {
if (writer != null) {
writer.close();
}
if (outputStream != null) {
outputStream.close();
}
if (bufferedReader != null) {
bufferedReader.close();
}
if (inputStreamReader != null) {
inputStreamReader.close();
}
if (inputStream != null) {
inputStream.close();
}
if (socket != null) {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}

}
}

客戶端:

package SocketStudy;

import java.io.*;
import java.net.Socket;
import java.util.Scanner;

public class SocketClient {
public static void main(String[] args) {
try {
Socket socket = new Socket("服務器的ip", 10068);
OutputStream outputStream = socket.getOutputStream();//獲得一個輸出流,用於向服務器發送數據
OutputStreamWriter writer=new OutputStreamWriter(outputStream,"UTF-8");//將寫入的字符編碼成字節後寫入一個字節流
System.out.println("請輸入數據:");
Scanner sc = new Scanner(System.in);
String data = sc.nextLine();
writer.write(data);
writer.flush();//刷新緩衝
socket.shutdownOutput();//只關閉輸出流而不關閉鏈接
//獲取服務器端的響應數據

InputStream inputStream = socket.getInputStream();//獲得一個輸入流,用於接收服務器響應的數據
InputStreamReader inputStreamReader = new InputStreamReader(inputStream,"UTF-8");//將一個字節流中的字節解碼成字符
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);//爲輸入流添加緩衝
String info = null;

       System.out.println("客戶端IP地址:"+socket.getInetAddress().getHostAddress());
            //輸出服務器端響應數據
while ((info = bufferedReader.readLine()) != null) {
System.out.println("客戶端接收:" + info);
}
//關閉資源
bufferedReader.close();
inputStreamReader.close();
inputStream.close();
writer.close();
outputStream.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

 

運行結果(先運行服務器端,再運行客戶端):

服務器:

 客戶端:

 

回車以後

客戶端:

 

 

服務器端:

 

 

在cmd下運行(先編譯再運行生成的.class文件,若是有中文,須要加encoding參數,當類中有導入本身建立的類時,須要切換到能包含該類的文件夾下執行命令,不然會報錯)

此時的服務器端:

相關文章
相關標籤/搜索