日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java 网络 socket 编程

發布時間:2025/3/19 java 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java 网络 socket 编程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

使用套接字實現基于 TCP 協議的服務器和客戶機程序

依據 TCP 協議,在 C/S 架構的通訊過程中,客戶端和服務器的 Socket 動作如下:

客戶端:

1.用服務器的 IP 地址和端口號實例化 Socket 對象。

2.調用 connect 方法,連接到服務器上。

3.將發送到服務器的 IO 流填充到 IO 對象里,比如 BufferedReader/PrintWriter。

4.利用 Socket 提供的 getInputStream 和 getOutputStream 方法,通過 IO 流對象,向服務器發送數據流。

5. 通訊完成后,關閉打開的 IO 對象和 Socket。

服務器:

1. 在服務器,用一個端口來實例化一個 ServerSocket 對象。此時,服務器就可以這個端口時刻監聽從客戶端發來的連接請求。

2.調用 ServerSocket 的 accept 方法,開始監聽連接從端口上發來的連接請求。

3.利用 accept 方法返回的客戶端的 Socket 對象,進行讀寫 IO 的操作通訊完成后,關閉打開的流和 Socket 對象。

?

下面是一個簡單的客戶端與服務器端的例子:

客戶端:

package my.socket.tcp;import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.InetAddress; import java.net.Socket; /** 上述客戶端代碼的主要業務邏輯是: 1. 同樣定義了通訊端口號,這里給出的端口號必須要和服務器端的一致。 2. 在 main 函數里,根據地址信息“localhost”,創建一個 InetAddress 類型的對象addr。這里,因為我們把客戶端和服務器端的代碼都放在本機運行,所以同樣可以用“127.0.0.1”字符串,來創建 InetAddress 對象。 3. 根據 addr 和端口號信息,創建一個 Socket 類型對象,該對象用來同服務器端的ServerSocket 類型對象交互,共同完成 C/S 通訊流程。 4. 同樣地創建 in 和 out 兩類 IO 句柄,用來向服務器端發送和接收數據流。 5. 通過 out 對象,向服務器端發送"Hello Server,I am …"的字符串。發送后,同樣可以用 in 句柄,接收從服務器端的消息。 6. 利用 out 對象,發送”byebye”字符串,用以告之服務器端,本次通訊結束。 7. 在 finally 從句里,關閉 Socket 對象,斷開同服務器端的連接。* @author asus**/ public class ClientCode {static String clientName = "Mike";// 端口號public static int portNo = 3333;public static void main(String[] args) throws IOException {// 設置連接地址類,連接本地InetAddress addr = InetAddress.getByName("localhost");// 要對應服務器端的 3333 端口號Socket socket = new Socket(addr, portNo);try {System.out.println("socket = " + socket);// 設置 IO 句柄BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())),true);out.println("Hello Server,I am " + clientName);String str = in.readLine();System.out.println(str);out.println("byebye");} finally {System.out.println("close the Client socket and the io.");socket.close();}} }

服務器端:

package my.socket.tcp;import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; /*** 編寫服務器端的主體代碼:這段代碼的主要業務邏輯是: 1. 在上述代碼里的 main 函數前,我們設置了通訊所用到的端口號,為 3333。 2. 在 main 函數里,根據給定 3333 端口號,初始化一個 ServerSocket 對象 s,該對象用來承擔服務器端監聽連接和提供通訊服務的功能。 3. 調用 ServerSocket 對象的 accept 方法,監聽從客戶端的連接請求。當完成調用accept 方法后,整段服務器端代碼將回阻塞在這里,直到客戶端發來 connect 請求。 4. 當客戶端發來 connect 請求,或是通過構造函數直接把客戶端的 Socket 對象連接到服務器端后,阻塞于此的代碼將會繼續運行。此時服務器端將會根據 accept 方法的執行結果,用一個 Socket 對象來描述客戶端的連接句柄。 5. 創建兩個名為 in 和 out 的對象,用來傳輸和接收通訊時的數據流。 6. 創建一個 while(true)的死循環,在這個循環里,通過 in.readLine()方法,讀取從客戶端發送來的 IO 流(字符串),并打印出來。如果讀到的字符串是“byebye”,那么退出while 循環。 7. 在 try…catch…finally 語句段里,不論在 try 語句段里是否發生異常,并且不論這些異常的種類,finally 從句都將會被執行到。在 finally 從句里,將關閉描述客戶端的連接句柄 socket 對象和 ServerSocket 類型的 s 對象。* @author asus**/ public class ServerCode {// 設置端口號public static int portNo = 3333;public static void main(String[] args) throws IOException {ServerSocket s = new ServerSocket(portNo);System.out.println("The Server is start: " + s);// 阻塞,直到有客戶端連接Socket socket = s.accept();try {System.out.println("Accept the Client: " + socket);// 設置 IO 句柄BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())),true);while (true) {String str = in.readLine();if (str.equals("byebye")) {break;}System.out.println("In Server reveived the info: " + str);out.println(str);}} finally {System.out.println("close the Server socket and the io.");socket.close();s.close();}} }

先運行服務器端,再運行客戶端之后,可以看到服務器端接收到來自客戶端發送的信息。


通常網絡編程都是用多線程來實現,將大大地提高服務器端的利用效率,并能使服務器端能具備完善的
服務功能。

package my.socket.tcp2;import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.InetAddress; import java.net.Socket; /*** 這個類的主要業務邏輯是: 1. 在構造函數里, 通過參數類型為 InetAddress 類型參數和 3333,初始化了本類 里的 Socket 對象,隨后實例化了兩類 IO 對象,并通過 start 方法,啟動定義在 run 方法內的 本線程的業務邏輯。 2. 在定義線程主體動作的 run 方法里,通過 IO 句柄,向 Socket 信道上傳輸本客戶 端的 ID 號,發送完畢后,傳輸”byebye”字符串,向服務器端表示本線程的通訊結束。 3. 同樣地,catch 從句將處理在 try 語句里遇到的 IO 錯誤等異常,而在 finally 從句 里,將在通訊結束后關閉客戶端的 Socket 句柄。* @author asus**/ class ClientThreadCode extends Thread {// 客戶端的 socketprivate Socket socket;// 線程統計數,用來給線程編號private static int cnt = 0;private int clientId = cnt++;private BufferedReader in;private PrintWriter out;// 構造函數public ClientThreadCode(InetAddress addr) {try {socket = new Socket(addr, 3333);} catch (IOException e) {e.printStackTrace();}// 實例化 IO 對象try {in = new BufferedReader(new InputStreamReader(socket.getInputStream()));out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);// 開啟線程start();} catch (IOException e) {// 出現異常,關閉 sockettry {socket.close();} catch (IOException e2) {e2.printStackTrace();}}}// 線程主體方法public void run() {try {out.println("Hello Server,My id is " + clientId);String str = in.readLine();System.out.println(str);out.println("byebye");} catch (IOException e) {e.printStackTrace();} finally {try {socket.close();} catch (IOException e) {e.printStackTrace();}}} } package my.socket.tcp2;import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.Socket; /** 這個類的業務邏輯說明如下: 1. 這個類通過繼承 Thread 類來實現線程的功能,也就是說,在其中的 run 方法里,定義了該線程啟動后要執行的業務動作。 2. 這個類提供了兩種類型的重載函數。在參數類型為 Socket 的構造函數里, 通過參數,初始化了本類里的 Socket 對象,同時實例化了兩類 IO 對象。在此基礎上,通過 start方法,啟動定義在 run 方法內的本線程的業務邏輯。 3. 在定義線程主體動作的 run 方法里,通過一個 for(;;)類型的循環,根據 IO 句柄,讀取從 Socket 信道上傳輸過來的客戶端發送的通訊信息。如果得到的信息為“byebye”,則表明本次通訊結束,退出 for 循環。 4. catch 從句將處理在 try 語句里遇到的 IO 錯誤等異常,而在 finally 從句里,將在通訊結束后關閉客戶端的 Socket 句柄。上述的線程主體代碼將會在 ThreadServer 類里被調用。* @author asus**/ public class ServerThreadCode extends Thread {// 客戶端的 socketprivate Socket clientSocket;// IO 句柄private BufferedReader sin;private PrintWriter sout;// 默認的構造函數public ServerThreadCode() {}public ServerThreadCode(Socket s) throws IOException {clientSocket = s;// 初始化 sin 和 sout 的句柄sin = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));sout = new PrintWriter(new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream())), true);// 開啟線程start();}// 線程執行的主體函數public void run() {try {// 用循環來監聽通訊內容for (;;) {String str = sin.readLine();// 如果接收到的是 byebye,退出本次通訊if (str.equals("byebye")) {break;}System.out.println("In Server reveived the info: " + str);sout.println(str);}System.out.println("closing the server socket!");} catch (IOException e) {e.printStackTrace();} finally {System.out.println("close the Server socket and the io.");try {clientSocket.close();} catch (IOException e) {e.printStackTrace();}}} } package my.socket.tcp2;import java.io.IOException; import java.net.InetAddress; /*** 這段代碼執行以后,在客戶端將會有 3 個通訊線程,每個線程首先將先向服務器端發送"Hello Server,My id is "的字符串,然后發送”byebye”,終止該線程的通訊。* @author asus**/ public class ThreadClient {public static void main(String[] args) throws IOException, InterruptedException {int threadNo = 0;InetAddress addr = InetAddress.getByName("localhost");for (threadNo = 0; threadNo < 3; threadNo++) {new ClientThreadCode(addr);}} } package my.socket.tcp2;import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; /** 這段代碼的主要業務邏輯說明如下: 1. 首先定義了通訊所用的端口號,為 3333。 2. 在 main 函數里,根據端口號,創建一個 ServerSocket 類型的服務器端的 Socket, 用來同客戶端通訊。 3. 在 for(;;)的循環里,調用 accept 方法,監聽從客戶端請求過來的 socket,請注意 這里又是一個阻塞。當客戶端有請求過來時,將通過 ServerThreadCode 的構造函數,創建一 個線程類,用來接收客戶端發送來的字符串。在這里我們可以再一次觀察 ServerThreadCode 類,在其中,這個類通過構造函數里的 start 方法,開啟 run 方法,而在 run 方法里,是通過 sin 對象來接收字符串,通過 sout 對象來輸出。 4. 在 finally 從句里,關閉服務器端的 Socket,從而結束本次通訊。* @author asus**/ public class ThreadServer {// 端口號static final int portNo = 3333;public static void main(String[] args) throws IOException {// 服務器端的 socketServerSocket s = new ServerSocket(portNo);System.out.println("The Server is start: " + s);try {for (;;) {// 阻塞,直到有客戶端連接Socket socket = s.accept();// 通過構造函數,啟動線程new ServerThreadCode(socket);}} finally {s.close();}} }

首先運行服務器端,再運行客戶端,可以清楚的看到服務器端多線程接收到來自客戶端的消息。


下面是同時開啟服務器端和客戶端,兩者進行不間斷的通信。

package my.socket.udp;import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; import java.net.UnknownHostException;public class ClientBean {// 描述 UDP 通訊的 DatagramSocket 對象private DatagramSocket ds;// 用來封裝通訊字符串private byte buffer[];// 客戶端的端口號private int clientport;// 服務器端的端口號private int serverport;// 通訊內容private String content;// 描述通訊地址private InetAddress ia;public ClientBean() throws SocketException, UnknownHostException {buffer = new byte[1024];clientport = 1985;serverport = 1986;content = "";ds = new DatagramSocket(clientport);ia = InetAddress.getByName("localhost");}public void sendToServer() throws IOException {buffer = content.getBytes();ds.send(new DatagramPacket(buffer, content.length(), ia, serverport));}// 以下是各屬性的 Get 和 Set 類型方法public byte[] getBuffer() {return buffer;}public void setBuffer(byte[] buffer) {this.buffer = buffer;}public int getClientport() {return clientport;}public void setClientport(int clientport) {this.clientport = clientport;}public String getContent() {return content;}public void setContent(String content) {this.content = content;}public DatagramSocket getDs() {return ds;}public void setDs(DatagramSocket ds) {this.ds = ds;}public InetAddress getIa() {return ia;}public void setIa(InetAddress ia) {this.ia = ia;}public int getServerport() {return serverport;}public void setServerport(int serverport) {this.serverport = serverport;} } package my.socket.udp;import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; import java.net.UnknownHostException;public class ServerBean {// 描述 UDP 通訊的 DatagramSocket 對象private DatagramSocket ds;// 用來封裝通訊字符串private byte buffer[];// 客戶端的端口號private int clientport;// 服務器端的端口號private int serverport;// 通訊內容private String content;// 描述通訊地址private InetAddress ia;public ServerBean() throws SocketException, UnknownHostException {buffer = new byte[1024];clientport = 1985;serverport = 1986;content = "";ds = new DatagramSocket(serverport);ia = InetAddress.getByName("localhost");}public void listenClient() throws IOException {// 在循環體里接收消息while (true) {// 初始化 DatagramPacket 類型的變量DatagramPacket dp = new DatagramPacket(buffer, buffer.length);// 接收消息,并把消息通過 dp 參數返回ds.receive(dp);content = new String(dp.getData(), 0, dp.getLength());// 打印消息print();}}public void print() {System.out.println(content);}public DatagramSocket getDs() {return ds;}public void setDs(DatagramSocket ds) {this.ds = ds;}public byte[] getBuffer() {return buffer;}public void setBuffer(byte[] buffer) {this.buffer = buffer;}public int getClientport() {return clientport;}public void setClientport(int clientport) {this.clientport = clientport;}public int getServerport() {return serverport;}public void setServerport(int serverport) {this.serverport = serverport;}public String getContent() {return content;}public void setContent(String content) {this.content = content;}public InetAddress getIa() {return ia;}public void setIa(InetAddress ia) {this.ia = ia;}} package my.socket.udp;import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader;public class UDPClient implements Runnable {public static String content;public static ClientBean client;public void run() {try {client.setContent(content);client.sendToServer();} catch (Exception ex) {System.err.println(ex.getMessage());}}// end of run// main 方法// …public static void main(String args[]) throws IOException {BufferedReader br = new BufferedReader(new InputStreamReader(System.in));client = new ClientBean();System.out.println("客戶端啟動...");while (true) {// 接收用戶輸入content = br.readLine();// 如果是 end 或空,退出循環if (content == null || content.equalsIgnoreCase("end") || content.equalsIgnoreCase("")) {break;}// 開啟新線程,發送消息new Thread(new UDPClient()).start();}} } package my.socket.udp;import java.io.IOException;public class UDPServer {public static void main(String args[]) throws IOException {System.out.println("服務器端啟動...");// 初始化 ServerBean 對象ServerBean server = new ServerBean();// 開啟監聽程序server.listenClient();} }

先運行服務器端,再運行客戶端。

在客戶端輸入想要發送的字符,在服務器端可以接收到。

總結

以上是生活随笔為你收集整理的Java 网络 socket 编程的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。