關(guān)于Socket的解析以及雙方通訊的java實(shí)現(xiàn)

在Java編程之中,我們通常都會接觸到網(wǎng)絡(luò)編程,那么不可避免地就會接觸到Socket通信,下面我將對Socket進(jìn)行簡單的解析,并給出雙方通訊的代碼實(shí)現(xiàn)方案

首先我們來介紹一下整個Socket的通信過程

Socket
  • 首先服務(wù)端先創(chuàng)建一個SocketServer,那么創(chuàng)建一個SocketServer需要我們指定端口號,如下
ServerSocket serverSocket=new ServerSocket(8888);

像上面這樣我們就簡單的開了一個端口號為8888的ServerSocket了

  • 接下來我們需要去接收來自客戶端的連接請求,也就是圖中的Other Socket,我們可以利用SockerServer的accept方法來建立連接,并且這個方法會返回一個Socket,用于和Other Socker進(jìn)行通信,簡單來說,我們就是利用SockerServer來獲取Socket,然后利用這個Socket和別人通信
  • 接下來我們獲取Socket的輸入輸出流,實(shí)現(xiàn)發(fā)送和接收信息,到此,我們已經(jīng)知道兩方進(jìn)行Socket通信的基本思路了

接下來我們來看看關(guān)于ServerSocket以及Socket的一些關(guān)鍵方法

ServerSocket

首先我們看一下ServerSocket的構(gòu)造方法,一共有4種:

  1. 無參的構(gòu)造方法 :
    ServerSocket(), 返回沒有綁定端口號的ServerSocket實(shí)例
  2. 含一個參數(shù)的構(gòu)造方法 :
    ServerSocket(int port),返回綁定給定端口號的ServerSocket實(shí)例
  3. 含兩個參數(shù)的構(gòu)造方法 :
    ServerSocket(int port, int backlog),返回綁定給定端口號的ServerSocket實(shí)例,并且設(shè)定同步隊(duì)列(syns queue)的大小
  4. 含三個參數(shù)的構(gòu)造方法:
    ServerSocket(int port, int backlog, InetAddress bindAddr),返回綁定給定端口號的ServerSocket實(shí)例,并且設(shè)定同步隊(duì)列(syns queue)的大小以及綁定給定的IP地址

主要看它的一些方法:

accept()

這個方法監(jiān)聽連接,一旦連接就返回一個Socket用于通信,需要注意的是,該方法為阻塞方法,如果沒有連接程序并不會繼續(xù)執(zhí)行下去

close()

關(guān)閉Socket,如果accept還在阻塞的話,就會拋出一個SocketException的異常

關(guān)于ServerSocket就不多加贅述了,我們來看一看Socket


Socket

構(gòu)造方法依然存在多種,這里只給出一個較為典型的

Socket(String host, int port),第一個參數(shù)是主機(jī)的IP地址作為字符串傳入,第二個參數(shù)為端口號

getInputStream(), getOutputStream()

獲得Socket的輸入輸出流,我們可以利用BufferReader以及PrintWriter來對這兩個流進(jìn)行操作,如下:

BufferReader reader = new BufferedReader(
                                new InputStreamReader(socket.getInputStream()));
PrintWriter  writer = new PrintWriter(
                                new OutputStreamWriter(socket.getOutputStream()));

下面簡單編寫一個雙方互相通信的java實(shí)現(xiàn)

  • 首先是服務(wù)端
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
/**
 * Created by Mezereon on 2017/3/1.
 */
public class TCPServer {
    private Socket socket;
    private ServerSocket serverSocket;
    private BufferedReader reader;
    private PrintWriter writer;
    private Scanner scanner = new Scanner(System.in);
    //開啟服務(wù)
    public void run() throws IOException {
            startTheSocket();
    }
    public void startTheSocket() throws IOException {
        serverSocket=new ServerSocket(18080); //打開18080端口等待連接
        acceptTheSocket();//接受連接并且初始化Socket,reader,writer
        openTheNewThreadToGetMessageFromClient();
        while(true) {      
              getYourMessage();//獲取鍵盤數(shù)據(jù)并作為輸入
        }
    }
    //接受連接并且初始化Socket,reader,writer
    private void acceptTheSocket() throws IOException {
        socket=serverSocket.accept();//阻塞方法,用于接受Socket連接
        System.out.println("Some one connect me ,it is "+socket.getLocalSocketAddress());//打印地址
        System.out.println("It's port is "+socket.getPort());//打印端口號
        reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));//獲得輸入流
        writer = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));//獲得輸出流
    }
    //掃描鍵盤并輸入數(shù)據(jù)
    private void getYourMessage() throws IOException {
        String yourMessage = scanner.nextLine();
        checkYourMessage(yourMessage);//檢查發(fā)送給客戶端的信息
        writer.println(yourMessage);//發(fā)送信息
        writer.flush();//flush方法用于清空緩沖區(qū),注意的是如果不flush你的信息可能發(fā)不出去一直存留在緩沖區(qū)
    }
    //用于檢查是否退出
    private void checkYourMessage(String yourMessage) throws IOException {
        //關(guān)閉各種
        if (yourMessage.equals("exit")) {
            socket.close();
            writer.close();
            reader.close();
            System.exit(0);
        }
    }
    //開啟一個新的線程來監(jiān)聽客戶端發(fā)來的信息
    private void openTheNewThreadToGetMessageFromClient() throws IOException {
        //開啟一個新的線程
        new Thread(new Runnable() {
            @Override
            public void run() {
                getTheMessageFromClient();
            }
        }).start();

    }
    //不斷循環(huán)來獲取客戶端發(fā)來的信息
    private void getTheMessageFromClient() {
        while(true) {
            String messageFromClient = null;
            try {
                messageFromClient = reader.readLine();
            } catch (IOException e) {
                e.printStackTrace();
            }
            printTheMessage(messageFromClient);//打印客戶端發(fā)來的信息
        }
    }
    //打印客戶端發(fā)來的信息
    private void printTheMessage(String messageFromClient) {
        if(messageFromClient!=null)
            System.out.println("He say:"+messageFromClient);
    }       
}

然后開始編寫客戶端:

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

/**
 * Created by Mezereon on 2017/2/27.
 */
public class TCPClient {

    private Socket socket;
    private BufferedReader reader ;
    private PrintWriter writer;
    private Scanner scanner = new Scanner(System.in);

    //開啟Socket來連接
    public void run() throws IOException{
            startTheSocket();
    }

    //開始連接服務(wù)端
    private void startTheSocket() throws IOException{
            toConnectTheServer();//創(chuàng)建Socket并初始化
            openTheThreadToReceiveInfoFromServer();//開啟一個新的線程來接受服務(wù)端發(fā)來的信息
            
            //一個循環(huán),用于讀取鍵盤的輸入
            while(true) {
                String yourMessage = scanner.nextLine();
                //不為空則發(fā)送信息
                if(yourMessage!=null) {
                    writer.println(yourMessage);
                    writer.flush();//記得flush清空緩沖區(qū)
                }
                //判斷是否退出
                if (yourMessage.equals("exit")) {
                    disConnect();
                    System.exit(0);
                }
            }
    }
    
    //創(chuàng)建一個Socket來連接本機(jī)的18080端口的服務(wù)端并初始化reader和writer
    private void toConnectTheServer() throws IOException {
        socket=new Socket("127.0.0.1",18080);
        reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        writer = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()),true);
    }

    private void openTheThreadToReceiveInfoFromServer() throws IOException {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    printMessage();//打印從服務(wù)端收到的信息
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    //循環(huán)不斷讀取服務(wù)端的信息
    private void printMessage() throws IOException {
        while (true) {
            String messageFromServer = null;
            try {
                messageFromServer = reader.readLine();//讀取信息
                System.out.println("He say:" + messageFromServer);//打印信息
            } catch (IOException e) {
                e.printStackTrace();
            } catch (NullPointerException e) {

            }
            if(messageFromServer.equals("exit")){
                disConnect();//關(guān)閉連接
                System.exit(0);
            }
        }
    }

    //關(guān)閉各種
    private void disConnect() throws IOException {
        socket.close();
        reader.close();
        writer.close();
    }

}

至此,關(guān)于Socket通信簡單的介紹以及利用java進(jìn)行簡單的通信的實(shí)現(xiàn)就結(jié)束了~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容