在Java中使用Socket模擬客戶端和服務端(多線程)

1:Socket與ServerSocket的交互java

111

2.Socket和ServerSocket介紹 編程

Socket 緩存

構造函數 服務器

Socket() 網絡

Socket(InetAddress address, int port)throws UnknownHostException, IOException session

Socket(InetAddress address, int port, InetAddress localAddress, int localPort)throws IOException 多線程

Socket(String host, int port)throws UnknownHostException, IOException(最簡單的鏈接方式) socket

Socket(String host, int port, InetAddress localAddress, int localPort)throws IOException ide

除去第一種不帶參數的以外,其它構造函數會嘗試創建與服務器的鏈接。若是失敗會拋出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;
    }

    @Override
    public void run() {

        //輸出流
        PrintWriter writer=null;
        //獲取客戶端輸入流,獲得客戶端發來的消息
        try {
            //讀取客戶端的數據
            //讀取到的一行數據
            String line=null;
            //客戶端發來的數據
            //開啓一個讀線程
           Thread write_thread= new Thread(new Runnable() {
                @Override
                public 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() {
                @Override
                public 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();
            }
        }


    }
}
相關文章
相關標籤/搜索