1. 程式人生 > >基於TCP/IP協議的Socket程式設計

基於TCP/IP協議的Socket程式設計

如今的大多數網路通訊都是選擇使用基於TCP/IP的協議進行,其中封裝的比較好的當屬socket了,下面就socket的使用進行詳細的描述:

一、Socket的工作模式

在TCP/IP網路應用中,通訊的兩個程序間相互作用的主要模式是客戶/伺服器(C/S)模式,即客戶向伺服器發出服務請求,伺服器接收到請求後,提供相應的服務。主要工作模式可以描述如下:

伺服器端:(首先伺服器要先啟動,伺服器根據請求提供相應服務)

(1)開啟一通訊通道並告知本地主機,它願意在某一公認地址上的某埠接收客戶請求;

(2)等待客戶請求到達該埠;

(3)接收到客戶端的服務請求時,處理該請求併發送應答訊號。當多工的伺服器接收到併發服務請求,會啟用一新程序來處理這個客戶請求。新程序處理此客戶請求,並不需要對其它請求作出應答。服務完成後,關閉此新程序與客戶的通訊鏈路,並終止。

(4)返回第(2)步,等待另一客戶請求。

(5)關閉伺服器

客戶端:

(1)開啟一通訊通道,並連線到伺服器所在主機的特定埠;

(2)向伺服器發服務請求報文,等待並接收應答;繼續提出請求

(3)請求結束後關閉通訊通道並終止。

二、工作原理


注:圖片來源於網路百度百科。

(1)建立連線(三次握手)

客戶端呼叫connect時,觸發了連線請求,向伺服器傳送資料包,然後connect進入阻塞狀態;伺服器監聽到連線請求呼叫accept函式接收請求向客戶端傳送確認資料包,然後accept進入阻塞狀態;客戶端收到伺服器的確認資料包之後connect返回,並對資料包進行確認;伺服器收到客戶端的資料包時accept返回,通過三次握手建立連線。

(2)進行通訊

伺服器根據客戶端的請求進行相應的應答。

(3)關閉連線(四次握手)

某個應用程序首先呼叫close主動關閉連線,這時TCP傳送一個結束訊號;伺服器接收訊號之後,執行被動關閉,

對這個訊號進行確認。伺服器傳送一個確認訊號給客戶端,接收到檔案結束符的應用程序呼叫close關閉它的socket,

最後向伺服器傳送一個確認訊號。

三、一個具體的例項實現伺服器和客戶端的通訊

伺服器:

package connection;

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

/**
 * Created with IntelliJ IDEA.
 * User: dsy
 * Date: 17-3-28
 * Time: 上午9:44
 * To change this template use File | Settings | File Templates.
 */
public class Server {

    public static void main(String args[]) throws IOException {
        int port = 5678;
        //定義一個ServerSocket監聽在埠5678上
        ServerSocket server = new ServerSocket(port);
        while (true) {
            //server嘗試接收其他Socket的連線請求(阻塞式的)
            Socket socket = server.accept();
            //接收到一個Socket就建立一個新執行緒來處理
            new Thread(new Task(socket)).start();
        }
    }

    /**
     * 用來處理Socket請求的
     */
    static class Task implements Runnable {

        private Socket socket;

        public Task(Socket socket) {
            this.socket = socket;
        }

        public void run() {
            try {
                handleSocket();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        /**
         * 跟客戶端Socket進行通訊
         */
        private void handleSocket() throws Exception {
            BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            StringBuilder sb = new StringBuilder();
            String temp;
            int index;
            while ((temp=br.readLine()) != null) {
                if ((index = temp.indexOf("end")) != -1) {//遇到end時就結束接收
                    sb.append(temp.substring(0, index));
                    break;
                }
                sb.append(temp);
            }
            System.out.println("receive from client: " + sb);
            //輸入傳送資訊
            System.out.println(" send info:");
            Writer writer = new OutputStreamWriter(socket.getOutputStream());
            Scanner in = new Scanner(System.in);
            String s = in.nextLine();
            writer.write(s);
            writer.write("end\n");
            writer.flush();
            writer.close();
            br.close();
            socket.close();
        }
    }
}
客戶端:
package connection;
import java.io.*;
import java.net.Socket;
import java.util.Scanner;

/**
 * Created with IntelliJ IDEA.
 * User: dsy
 * Date: 17-3-28
 * Time: 上午9:52
 * To change this template use File | Settings | File Templates.
 */
public class Client {

    public static void main(String args[]) throws Exception {
        String host = "localhost";  //要連線的伺服器IP地址
        int port = 5678;   //要連線的伺服器埠號
        //與伺服器建立連線
        Socket client = new Socket(host, port);
        //往服務端寫資料
        System.out.println("Send info:");
        Writer writer = new OutputStreamWriter(client.getOutputStream());
        Scanner in = new Scanner(System.in);
        String s = in.nextLine();
        writer.write(s);
        writer.write("end\n");
        writer.flush();
        //從伺服器接受資料
        BufferedReader br = new BufferedReader(new InputStreamReader(client.getInputStream()));
        StringBuffer sb = new StringBuffer();
        String temp;
        int index;
        while ((temp=br.readLine()) != null) {
            if ((index = temp.indexOf("end")) != -1) {
                sb.append(temp.substring(0, index));
                break;
            }
            sb.append(temp);
        }
        System.out.println("receive from server: " + sb);
        writer.close();
        br.close();
        client.close();
    }
}