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


 要想詳細了解socket,大家請自行百度,我這里只簡單介紹。

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

  TCP是基於連接的協議,在收發數據前,需要建立可靠的連接,也就是所謂的三次握手。使用TCP協議時,數據會准確到達,但是效率較低。

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

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

              服務器端              客戶端

           創建服務器端的socket        創建客戶端的socket

           綁定端口號             連接服務器端的端口

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

           接收客戶端的連接請求        關閉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參數,當類中有導入自己創建的類時,需要切換到能包含該類的文件夾下執行命令,否則會報錯)

此時的服務器端:

 

 

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM