在Java中使用Socket模拟客户端和服务端(多线程)
1:Socket與ServerSocket的交互
2.Socket和ServerSocket介紹
Socket
構造函數
Socket()
Socket(InetAddress address, int port)throws UnknownHostException, IOException
Socket(InetAddress address, int port, InetAddress localAddress, int localPort)throws IOException
Socket(String host, int port)throws UnknownHostException, IOException(最簡單的連接方式)
Socket(String host, int port, InetAddress localAddress, int localPort)throws IOException
除去第一種不帶參數的之外,其它構造函數會嘗試建立與服務器的連接。如果失敗會拋出IOException錯誤。如果成功,則返回Socket對象。
InetAddress是一個用于記錄主機的類,其靜態getHostByName(String msg)可以返回一個實例,其靜態方法getLocalHost()也可以獲得當前主機的IP地址,并返回一個實例。
Socket(String host, int port, InetAddress localAddress, int localPort)構造函數的參數分別為目標IP、目標端口、綁定本地IP、綁定本地端口。
Socket方法
getInetAddress();??? 遠程服務端的IP地址
getPort();??? 遠程服務端的端口
getLocalAddress()??? 本地客戶端的IP地址
getLocalPort()??? 本地客戶端的端口
getInputStream();??? 獲得輸入流
getOutStream();??? 獲得輸出流
值得注意的是,在這些方法里面,最重要的就是getInputStream()和getOutputStream()了。
Socket狀態
isClosed();???? //連接是否已關閉,若關閉,返回true;否則返回false
isConnect(); //如果曾經連接過,返回true;否則返回false
isBound();???? //如果Socket已經與本地一個端口綁定,返回true;否則返回false
ServerSocket
構造函數
ServerSocket()throws IOException
ServerSocket(int port)throws IOException
ServerSocket(int port, int backlog)throws IOException
ServerSocket(int port, int backlog, InetAddress bindAddr)throws IOException
注意點:
1. port服務端要監聽的端口;backlog客戶端連接請求的隊列長度;bindAddr服務端綁定IP
2. 如果端口被占用或者沒有權限使用某些端口會拋出BindException錯誤。譬如1~1023的端口需要管理員才擁有權限綁定。
3. 如果設置端口為0,則系統會自動為其分配一個端口;
4. bindAddr用于綁定服務器IP,為什么會有這樣的設置呢,譬如有些機器有多個網卡。
5. ServerSocket一旦綁定了監聽端口,就無法更改。ServerSocket()可以實現在綁定端口前設置其他的參數。
3.實例前說明
Socket網絡編程主要用于兩臺機器之間的數據傳輸,大致過程為:建立連接→信息傳遞→關閉連接。我們可以理解為服務器(ServerSocket)和客戶端(Socket),服務器提供連接服務,客戶端鏈接服務器。因為服務器需要向多臺客戶端提供服務,所以需要一直保持監聽狀態,不斷地監聽客戶端請求,在這個過程中,ServerSocket一直處于阻斷狀態,直到有客戶端連接,馬上返回一個Socket對象,然后通過IO流傳輸數據,在這個過程中,當有數據傳輸的時候,IO流才被激活,其余時間都處于阻斷狀態,等待數據發送過來,然后進行處理。
注意:
當我們發送數據的時候,必須使用flush()方法,將數據提交,否則只會存在于緩沖中,不會發送數據,有時候即使我們使用flush()方法,也無法從另一臺電腦上讀取到數據,這是因為Socket會將數據先存儲起來,等到數據量達到一定大小的時候,會一起提交(或者這樣理解,flush()會根據換行符’\n’判斷用戶是否完成輸入,如果沒有看到’\n’,Socket認為用戶數據還沒有寫完,仍在保留在緩存池中)所以我們可以在要提交的數據加上’\n’強制提交就可以了。
不過,如果我們沒必要很多的交互,只需要交互一次就可以了,就可以不在乎這些,當關閉Socket的輸入輸出流的時候,Socket會將緩存池中的數據全部提交到另一臺機器。
最后最重要的,當我們用完流的時候,一定要及時關閉,養成良好的習慣。
在下面的實例中,我通過多線程的方式保證服務器和客戶端一直處于數據交互狀態,并且使用線程池的方式維護線程。、
線程類:
package com.best.alivn.socketservice; import java.io.*; import java.net.Socket; import java.util.Scanner;/**讓服務器處理與客戶端通訊放在線程中* Created by Alivn on 2017/3/18.*/ public class SessionThread implements Runnable{private final Socket client;private static Integer Tag=0;public SessionThread(Socket client) {this.client = client;}@Overridepublic void run() {//輸出流PrintWriter writer=null;//獲取客戶端輸入流,得到客戶端發來的消息try {//讀取客戶端的數據//讀取到的一行數據String line=null;//客戶端發來的數據//開啟一個讀線程Thread write_thread= new Thread(new Runnable() {@Overridepublic void run() {//輸入流InputStream inputStream=null;BufferedReader reader=null;try {while (true) {inputStream= client.getInputStream();//為了提高效率,轉換成字符流reader=new BufferedReader(new InputStreamReader(inputStream));String line=null;while ((line=reader.readLine())!=null){System.out.println(line);}}} catch (IOException e) {//流異常 e.printStackTrace();}finally {//關閉流try {inputStream.close();reader.close();} catch (IOException e) {e.printStackTrace();}}}});write_thread.start();//獲取輸出流,往客戶端發送數據writer=new PrintWriter(client.getOutputStream());//客戶端剛連接的時候,客戶端反饋信息String send_msg ="您已成功連接到服務器......--[Server]";writer.println(send_msg);writer.flush();//可以多次發送//從鍵盤輸入while ("1".equals("1")) {Scanner scanner=new Scanner(System.in);send_msg =scanner.nextLine()+"--[Server]";writer.println(send_msg);//注意(我們發送數據的時候,flush方法會提交我們的數據,但是還不會發送,當數據達到一定容量才會發送,// 或者讀到換行符的時候發送) writer.flush();}} catch (IOException e) {//獲取客戶端輸入流失敗 e.printStackTrace();}finally {//關閉流try {client.shutdownInput();client.shutdownOutput();writer.close();} catch (IOException e) {//關閉輸入輸出流失敗 e.printStackTrace();}}} }服務器類:
package com.best.alivn.socketservice; import scala.actors.threadpool.ExecutorService; import scala.actors.threadpool.Executors; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket;/**服務器* Created by Alivn on 2017/3/18.*/ public class Server {//甚至端口號private final static Integer PORT=8888;//設置開啟的線程數private final static Integer THREAD_SIZE=5;//創建線程池private static ExecutorService executorService=null;public static void main(String[]args){executorService = Executors.newFixedThreadPool(THREAD_SIZE);//創建服務器套接字try {//創建三個線程放入到線程池中....ServerSocket serverSocket=new ServerSocket(PORT);//開啟服務器,一直處于監聽的狀態System.out.println("[Server]:服務器已啟動.........");while (true){//服務器根據端口號,監聽客戶端鏈接,Socket client = serverSocket.accept();System.out.println("[Server]:有客戶端鏈接至服務器.......");//將交互放到線程中SessionThread session=new SessionThread(client);//放入到線程池中 session.run();executorService.execute(session);}} catch (IOException e) {//實例化服務器失敗 e.printStackTrace();}}}客戶端類: package com.best.alivn.socketservice; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; import java.util.Scanner;/**客戶端* Created by Alivn on 2017/3/18.*/ public class Client {private final static String host="localhost";private final static Integer port=8888;public static void main(String[] args) {Socket socket=null;//輸入流BufferedReader reader=null;//創建客戶端對象try {//連接服務器socket=new Socket(host,port);//客戶端剛連接的時候,客戶端反饋信息//輸出流final PrintWriter writer=new PrintWriter(socket.getOutputStream());;String send_msg ="你好,我是小白......--[Client]";writer.println(send_msg);writer.flush();//開啟一個線程,處理循環Thread write_Stream= new Thread(new Runnable() {@Overridepublic void run() {//循環輸入數據Scanner scanner=new Scanner(System.in);while ("1".equals("1")){String send_msg=scanner.nextLine()+"--[Client]";writer.println(send_msg);writer.flush();}}});write_Stream.start();while ("1".equals("1")) {//獲取輸入流,得服務端的數據reader=new BufferedReader(new InputStreamReader(socket.getInputStream()));String line=null;while ((line=reader.readLine())!=null){System.out.println(line);}}writer.close();} catch (IOException e) {//鏈接失敗 文件讀取失敗 e.printStackTrace();}finally {//關閉流try {reader.close();socket.shutdownInput();socket.shutdownOutput();} catch (IOException e) {e.printStackTrace();}}} }轉載于:https://www.cnblogs.com/ljp-sun/p/6576720.html
總結
以上是生活随笔為你收集整理的在Java中使用Socket模拟客户端和服务端(多线程)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: win10打开安装的软件闪退怎么办 wi
- 下一篇: PHP中文件操作基础:目录操作,文件操作