天天看點

Java中網絡程式設計之TCP協定

一、TCP的基本概念

TCP是專門設計用于在不可靠的英特網上提供可靠的、端到端的位元組流通信的協定,是一個面向連接配接的協定,TCP連接配接是位元組流而非封包流。UDP和TCP各有65536個端口号互不影響。

二、單線程服務端

以下代碼隻能實作服務端和用戶端的同步對話。服務端處理完一個用戶端請求,才會處理另一個用戶端請求。伺服器端的輸出效果是Client1阻塞20秒,Client2不會執行。必須等Client1阻塞結束之後,Client2才會執行。該例子可用來學習TCP的基本文法。

/**  

 * TCP用戶端1  

 *   

 * @author 徐越  

 */ 

public class Client1  

{  

    public static void main(String[] args) throws Exception  

    {  

        Socket socket = new Socket("127.0.0.1", 8821);  

        OutputStream os = socket.getOutputStream();  

        String msg = "我是徐越1";  

        Thread.sleep(20000);  

        os.write(msg.getBytes());  

        os.flush();  

        os.close();socket.close();    

    }  

}  

 * TCP用戶端2  

public class Client2  

        String msg = "我是徐越2";  

 * 單線程TCP服務端  

public class Server  

        // 建立端口為8821的TCP伺服器端對象  

        // 8821是伺服器端的端口号而用戶端從某端口A連到8821,端口A是随機的  

        ServerSocket serverSocket = new ServerSocket(8821);  

        while (true)  

        {  

            // 若無用戶端發送請求則線程在此阻塞,方法不繼續執行  

            Socket socket = serverSocket.accept();  

            System.out.println("connected");  

            InputStream instream = socket.getInputStream();  

            ByteArrayOutputStream bos = new ByteArrayOutputStream();  

            int len = 0;  

            byte[] buffer = new byte[1024];  

            while ((len = instream.read(buffer)) != -1)  

            {  

                bos.write(buffer, 0, len);  

            }  

            instream.close();  

            bos.flush();  

            bos.close();  

            String msg = bos.toString();  

            System.out.println("用戶端的IP:" + socket.getInetAddress().getHostAddress());  

            System.out.println("用戶端的端口:" + socket.getPort());  

            System.out.println("用戶端的資訊:" + msg);  

        }  

執行結果

connected

用戶端的IP:127.0.0.1

用戶端的端口:3775

用戶端的資訊:我是徐越1

用戶端的端口:3787

用戶端的資訊:我是徐越2

三、多線程伺服器

在實際應用中是在伺服器上運作一個永久的程式,接收來自其他多個用戶端的請求,提供相應的服務。需要利用多線程實作多客戶機制。伺服器在指定的端口上監聽是否有客戶請求,一旦監聽到就會啟動一個專門的服務線程來響應該請求,而伺服器本身在啟動完線程之後馬上又進入監聽狀态,等待下一個客戶的到來。隻要将服務端為如下代碼,Client1和Client2就會異步執行。

 * 多線程服務端0  

public class MultiThreadServer0  

    // 端口号  

    private int port = 8821;  

    // 服務端  

    private ServerSocket serverSocket;  

    public MultiThreadServer0() throws IOException  

        // 建立伺服器端  

        serverSocket = new ServerSocket(port);  

        System.out.println("伺服器啟動");  

    public void service()  

            Socket socket = null;  

            try 

                // 用戶端進行連接配接時會觸發accept方法進而建立連接配接  

                socket = serverSocket.accept();  

                new MultiThreadHandler(socket).start();  

            catch (Exception e)  

                e.printStackTrace();  

    public static void main(String[] args) throws IOException  

        new MultiThreadServer1().service();  

 * 多線程處理類  

class MultiThreadHandler extends Thread  

    private Socket socket;  

    public MultiThreadHandler(Socket socket)  

        this.socket = socket;  

    private BufferedReader getReader(Socket socket) throws IOException  

        InputStream socketIn = socket.getInputStream();  

        // InputStreamReader為轉換流  

        // InputStream本是位元組流,現加一個Reader,表示用字元流的方式讀取位元組流  

        InputStreamReader isr = new InputStreamReader(socketIn);  

        return new BufferedReader(isr);  

    public void run()  

        try 

            BufferedReader br = getReader(socket);  

            String msg = null;  

            while ((msg = br.readLine()) != null)  

                System.out.println("用戶端的IP:" + socket.getInetAddress().getHostAddress());  

                System.out.println("用戶端的端口:" + socket.getPort());  

                System.out.println("用戶端的資訊:" + msg);  

        catch (IOException e)  

            e.printStackTrace();  

        finally 

                if (socket != null)  

                {  

                    socket.close();  

                }  

            catch (IOException e)  

 * 多線程服務端1  

public class MultiThreadServer1  

    // 線程池  

    private ExecutorService executorService;  

    // 單個CPU線程池大小  

    private final int POOL_SIZE = 10;  

    public MultiThreadServer1() throws IOException  

        // 擷取目前系統的CPU數目  

        int cpuNums = Runtime.getRuntime().availableProcessors();  

        // 根據系統資源情況靈活定義線程池大小  

        executorService = Executors.newFixedThreadPool(cpuNums * POOL_SIZE);  

                // 客戶進行連接配接就會觸發accept方法進而建立連接配接  

                // 調用線程池操作  

                executorService.execute(new Handler(socket));  

class Handler implements Runnable  

    public Handler(Socket socket)  

 兩個多線程服務端執行結果相同

伺服器啟動

用戶端的端口:3931

用戶端的端口:3928

參考位址:http://www.2cto.com/kf/201209/158518.html

本文轉自IT徐胖子的專欄部落格51CTO部落格,原文連結http://blog.51cto.com/woshixy/1098701如需轉載請自行聯系原作者

woshixuye111