2019-08-21 基于TCP協(xié)議的Socket通信

Socket

套接字使用TCP提供了兩臺計算機(jī)之間的通信機(jī)制。 客戶端程序創(chuàng)建一個套接字,并嘗試連接服務(wù)器的套接字。
當(dāng)連接建立時,服務(wù)器會創(chuàng)建一個 Socket 對象??蛻舳撕头?wù)器現(xiàn)在可以通過對 Socket 對象的寫入和讀取來進(jìn)行通信。
java.net.Socket 類代表一個套接字,并且 java.net.ServerSocket 類為服務(wù)器程序提供了一種來監(jiān)聽客戶端,并與他們建立連接的機(jī)制。
以下步驟在兩臺計算機(jī)之間使用套接字建立TCP連接時會出現(xiàn):
服務(wù)器實例化一個 ServerSocket 對象,表示通過服務(wù)器上的端口通信。
服務(wù)器調(diào)用 ServerSocket 類的 accept() 方法,該方法將一直等待,直到客戶端連接到服務(wù)器上給定的端口。
服務(wù)器正在等待時,一個客戶端實例化一個 Socket 對象,指定服務(wù)器名稱和端口號來請求連接。
Socket 類的構(gòu)造函數(shù)試圖將客戶端連接到指定的服務(wù)器和端口號。如果通信被建立,則在客戶端創(chuàng)建一個 Socket 對象能夠與服務(wù)器進(jìn)行通信。
在服務(wù)器端,accept() 方法返回服務(wù)器上一個新的 socket 引用,該 socket 連接到客戶端的 socket。
連接建立后,通過使用 I/O 流在進(jìn)行通信,每一個socket都有一個輸出流和一個輸入流,客戶端的輸出流連接到服務(wù)器端的輸入流,而客戶端的輸入流連接到服務(wù)器端的輸出流。
TCP 是一個雙向的通信協(xié)議,因此數(shù)據(jù)可以通過兩個數(shù)據(jù)流在同一時間發(fā)送.

Socket 類的構(gòu)造方法和普通方法





用Socket類實現(xiàn)客戶端向服務(wù)器端發(fā)送消息

/**
 * 網(wǎng)絡(luò)編程:
 * 在兩臺不同的計算機(jī)之間傳遞數(shù)據(jù)
 *
 * 客戶端:Apps 瀏覽器 pc軟件
 * 服務(wù)器端:存儲/處理數(shù)據(jù)
 *
 * URL:統(tǒng)一的資源定位
 * http:www.baidu.com/search?code=android&type=1
 * http/https: 傳輸協(xié)議 Tcp/IP
 * www.baidu.com : 域名 表示一臺網(wǎng)絡(luò)中的電腦
 *                 ipv4 ipv6地址:唯一標(biāo)識一臺網(wǎng)絡(luò)中的計算機(jī)
 *                  32位: 4個部分每個8字節(jié)
 *
 * DNS服務(wù)器:域名解析
 * 將www.baidu.com類型的域名解析為對應(yīng)的ip地址
 * search 對應(yīng)的后臺程序文件 php java jsp
 * ? 表示運(yùn)行這個程序需要傳遞的參數(shù)
 * code=android code是服務(wù)器端規(guī)定的字段
 * & 如果有多個參數(shù)使用&符號鏈接
 *
 * ip地址:唯一標(biāo)識某一臺電腦
 * 端口號:唯一標(biāo)識電腦上的某一個進(jìn)程(程序)80
 *
 * 數(shù)據(jù)傳輸:TCP/IP協(xié)議
 * TCP:面向鏈接的 安全的
 * UDP:面向無鏈接的 不安全 但快
 *
 * 網(wǎng)絡(luò)中的數(shù)據(jù)傳輸:Socket
 * Socket:客戶端
 * ServerSocket:服務(wù)器端
 * */
//模擬客戶端
class Client {
    public static void main(String[] args) throws IOException {
        //1.創(chuàng)建用于通信的socket
        //  指明和誰通信:ip地址  端口號
        Socket socket = new Socket("ip",8989);
        // 接收服務(wù)器端的數(shù)據(jù)
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        //讀取服務(wù)器端發(fā)來的數(shù)據(jù)
        String line = null;
        while ((line = br.readLine()) != null){
            System.out.println(line);
        }

        // 客戶端向服務(wù)器端發(fā)送數(shù)據(jù)
        PrintStream ps = new PrintStream(socket.getOutputStream());
        ps.println("你好啊");
        socket.shutdownOutput();
    }
}

//模擬服務(wù)器端
class Server{
    public static void main(String[] args) throws IOException {
        //1.創(chuàng)建服務(wù)器端的serverocket
        ServerSocket ss = new ServerSocket(8989);

        //2.獲取連接的客戶端的socket
        Socket clientSocket = ss.accept();

        //3.向客戶端發(fā)送數(shù)據(jù)
        //BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
        PrintStream ps = new PrintStream(clientSocket.getOutputStream());
        ps.println("登錄成功");
        clientSocket.shutdownOutput();

        //4.接收客戶端發(fā)來的數(shù)據(jù)
        BufferedReader br = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
        String line = null;
        while ((line = br.readLine()) != null){
            System.out.println(line);
        }
    }
}

升級版:消息由終端手動輸入:

/**
 * 手動輸入內(nèi)容 發(fā)送
 * Socket扮演的是客戶端
 * ServerSocket扮演的是服務(wù)器端
 *
 */
class MyClient {
    public static void main(String[] args){
        //連接服務(wù)器端的socket
        Socket socket = null;
        try{
            socket = new Socket("ip",8888);

            //接收服務(wù)器端信息
            BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String line;
            while ((line = br.readLine()) != null){
                System.out.println(line);
            }

            //從鍵盤輸入數(shù)據(jù) 發(fā)送給服務(wù)器端
        } catch (IOException e) {
            System.out.println("網(wǎng)絡(luò)出錯 請重新登錄");
        } finally {
            //關(guān)閉連接
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

class MyServer {
    public static void main(String[] args){
        //創(chuàng)建ServerSocket
        try (ServerSocket ss = new ServerSocket(8888)){
            //監(jiān)聽客戶端的連接
            Socket socket = ss.accept();

            //從終端接收數(shù)據(jù)
            BufferedReader keyin = new BufferedReader(new InputStreamReader(System.in));
            //獲取向客戶端輸出數(shù)據(jù)的輸出流
            PrintStream ps = new PrintStream(socket.getOutputStream());
            String line = null;

            while ((line = keyin.readLine()) != null){
                //發(fā)送給客戶端
                ps.println(line);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

實現(xiàn)客戶端向服務(wù)器端發(fā)送圖片:

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Meida {
}

class MeidaClient{
    public static void main(String[] args) throws IOException {
        //連接服務(wù)器 獲取socket
        Socket socket = new Socket("ip",8080);

        //創(chuàng)建服務(wù)器端對應(yīng)的輸入流 用于接收服務(wù)器端發(fā)來的數(shù)據(jù)
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        System.out.println(br.readLine());

        //向服務(wù)器端發(fā)送文件(圖片)
        //1.將文件寫入到內(nèi)存里
        String path = "D:\\桌面\\pokerplaymind.png";
        FileInputStream fis = new FileInputStream(path);

        //2.創(chuàng)建字節(jié)流 outputStream
        BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
        byte[] buf = new byte[1024];
        int len;
        while ((len = fis.read(buf)) != -1){
            bos.write(buf,0,len);
        }
        socket.shutdownOutput();
    }
}

class MediaServer{
    public static void main(String[] args) throws IOException {
        //創(chuàng)建服務(wù)器端的ServerSoket
        ServerSocket ss = new ServerSocket(8080);

        //監(jiān)聽客戶端連接
        //當(dāng)有客戶端來連接這個服務(wù)器 就可以得到對應(yīng)的socket
        //當(dāng)沒有客戶端來連接 服務(wù)器一直在這里等待
        Socket socket = ss.accept();

        //創(chuàng)建客戶端對應(yīng)的輸出流 用于向這個客戶端發(fā)送數(shù)據(jù)
        PrintStream ps = new PrintStream(socket.getOutputStream());
        ps.println("連接成功 可以發(fā)數(shù)據(jù)了!");

        BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
        String path = "D:\\Android learning\\java2\\821Day13\\src\\main\\java\\swu\\w1nfred\\a821day13\\1.png";
        FileOutputStream fos = new FileOutputStream(path);

        byte[] buf = new byte[1024];
        int len;
        while((len = bis.read(buf)) != -1){
            fos.write(buf,0,len);
        }
    }
}

多線程實現(xiàn)單服務(wù)器多客戶端傳遞數(shù)據(jù):

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;

public class Myclass {
}
/**
 *
 *
 * */
class Server{
    //保存每一個連接過來的Socket對象
    public static ArrayList<Socket> sockets = new ArrayList<>();
    public static void main(String[] args)throws IOException {

        ServerSocket ss  =new ServerSocket(8888);

        //不停的等待客戶端來連接
        while(true) {
            Socket socket = ss.accept();
            //當(dāng)有客戶端連接過來 就保存
            sockets.add(socket);

            //開啟一個線程 處理每個客戶端的輸入
            new ServerThread(socket).start();
        }
    }
}

class ServerThread extends Thread{
    private Socket socket;
    public ServerThread(Socket socket){
        this.socket = socket;
    }

    @Override
    public void run() {
        BufferedReader br = null;
        try {
            br= new BufferedReader(new InputStreamReader(socket.getInputStream()));
            String line = null;
            while((line = br.readLine())!=null){
                //群發(fā)消息
                //遍歷Server維護(hù)的數(shù)組
                for (Socket s:Server.sockets) {
                    //向socket對應(yīng)的客戶端發(fā)送消息
                    PrintStream ps =  new PrintStream(s.getOutputStream());
                    ps.println(line);


                }
            }
        } catch (IOException e) {
            System.out.println("網(wǎng)絡(luò)錯誤 請重新登錄");
            System.exit(-1);
        }finally {
            //關(guān)閉輸入輸出流
            //關(guān)閉對應(yīng)的socket連接
            try {
                if(br != null){
                    br.close();}
                if(socket !=null){
                    socket.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        super.run();
    }
}
class Client{
    public static void main(String[] args)throws IOException {
        Socket socket = new Socket("ip",8888);
        //主線程處理終端輸入 發(fā)送給服務(wù)器端
        //用一個子線程處理服務(wù)器端數(shù)據(jù)
        new Thread(new ClientThread(socket)).start();

        BufferedReader keyin = new BufferedReader(new InputStreamReader(System.in));
        PrintStream ps = new PrintStream(socket.getOutputStream());
        String line = null;
        while((line = keyin.readLine())!=null){
            ps.println(line);
        }




    }
}
/**
 * 創(chuàng)建一個子線程處理客戶端接收服務(wù)器端數(shù)據(jù)
 *
 * */
class ClientThread implements Runnable{
    private Socket socket;

    public ClientThread(Socket socket){
        this.socket = socket;
    }
    @Override
    public void run() {
        BufferedReader br = null;
        try {
            //獲取服務(wù)器端的輸入流對象
            br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            //讀取數(shù)據(jù)
            String line;
            while((line = br.readLine())!=null){
                System.out.println(line);
            }

        } catch (IOException e) {
            System.out.println("網(wǎng)絡(luò)出錯 請重新登錄");
            System.exit(-1);
        }finally {
            if(br != null){
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(socket !=null){
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }
    }
}
chaos
最后編輯于
?著作權(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ù)。

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