1. 程式人生 > >通過多執行緒實現非阻塞TCP通訊

通過多執行緒實現非阻塞TCP通訊

在tcp通訊中,一般都是阻塞的,如果要實現非阻塞,我們可以使用多執行緒也可以使用nio中相關的類。這裡我使用的是多執行緒的方式實現非阻塞。
伺服器端:
1.建立ServerSocket物件,繫結監聽埠;
2.呼叫accept()方法對客戶端進行監聽;
3.使用多執行緒對使用者進行讀操作,並反饋;
客戶端:
1.建立Socket物件,通過IP和埠號和伺服器進行連線;
2.分別使用多執行緒對伺服器端進行讀寫操作;
程式碼如下:
伺服器端:

package sency.one;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import
java.io.IOException; import java.net.ServerSocket; import java.net.Socket; public class Server { private ServerSocket ss; private int port = 8000; public Server() throws IOException { // 建立接收端的ServerSocket ss = new ServerSocket(port); System.out.println("伺服器啟動!!!"); } public
static void main(String args[]) throws IOException { new Server().service(); } private void service() { // TODO Auto-generated method stub while (true) { Socket socket = null; try { // 通過accept()方法進行監聽,返回一個socket socket = ss.accept(); DataOutputStream os = new
DataOutputStream(socket.getOutputStream()); package sency.one; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; public class Server { private ServerSocket ss; private int port = 8000; public Server() throws IOException { // 建立接收端的ServerSocket ss = new ServerSocket(port); System.out.println("伺服器啟動!!!"); } public static void main(String args[]) throws IOException { new Server().service(); } private void service() { // TODO Auto-generated method stub while (true) { Socket socket = null; try { // 通過accept()方法進行監聽,返回一個socket socket = ss.accept(); DataOutputStream os = new DataOutputStream(socket.getOutputStream()); os.writeUTF("Welcome!"); os.flush(); //輸出客戶端埠 if (socket.isConnected()) { System.out.println("Port:" + socket.getPort()); } // 採用多執行緒的方式處理 // 收資訊執行緒 Thread receiveThread = new Thread(new ReHandler(socket)); receiveThread.start(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } // 收資訊 class ReHandler implements Runnable { private Socket socket = null; public ReHandler(Socket socket) { this.socket = socket; } public void run() { try { printMsg(socket); } catch (IOException e) { e.printStackTrace(); } finally { try { if (socket != null) { socket.close(); } } catch (IOException e) { e.printStackTrace(); } } } } // 在伺服器端輸出客戶端傳送的資訊 private void printMsg(Socket socket) throws IOException { DataInputStream is = new DataInputStream(socket.getInputStream()); String msg = ""; while ((msg = is.readUTF()) != null) { System.out.println("來自:"+socket.getInetAddress()+"--"+socket.getPort()); System.out.println("#Client:" + msg); if (msg.equals("bye")) { break; } sendEcho(socket,msg); } is.close(); } // 向客戶端傳送資訊 private void sendEcho(Socket socket,String msg) throws IOException { if(msg!=null){ DataOutputStream os = new DataOutputStream(socket.getOutputStream()); os.writeUTF("#Server:收到"+msg); os.flush(); } } }

客戶端:

package sency.one;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;

public class Client {
    private Socket socket;
    private String host = "localhost";
    private int port = 8000;

    public Client() throws IOException {
        socket = new Socket(host, port);
        System.out.println("客戶端啟動!!!");
        System.out.println("Port:"+socket.getLocalPort());
    }

    public static void main(String args[]) throws IOException {
        new Client().talk();
    }

    private void talk() {
        // TODO Auto-generated method stub
        // 採用多執行緒分別進行收發資訊
        // 傳送執行緒
        Thread sendThread = new Thread(new SendHandler());
        sendThread.start();

        // 收執行緒
        Thread reThread = new Thread(new ReHandler());
        reThread.start();
    }

    class SendHandler implements Runnable {
        public void run() {
            // TODO Auto-generated method stub
            try {
                sendMsg();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }finally {
                try {
                    if (socket != null) {
                        socket.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

    class ReHandler implements Runnable {

        public void run() {
            // TODO Auto-generated method stub
            try {
                receiveMsg();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }finally {
                try {
                    if (socket != null) {
                        socket.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

    //發信息
    public void sendMsg() throws IOException {
        DataOutputStream os = new DataOutputStream(socket.getOutputStream());
        DataInputStream is = new DataInputStream(System.in);
        String msg = null;
        while ((msg = is.readLine()) != null) {
            System.out.println("#Client:" + msg);
            os.writeUTF(msg);
            os.flush();
            if(msg.equals("bye")){
                break;
            }
        }   
        os.close();
        is.close();
    }

    //收資訊
    private void receiveMsg() throws IOException{
        DataInputStream is = new DataInputStream(socket.getInputStream());
        String msg = null;
        while((msg = is.readUTF())!=null){
            System.out.println("#Service:"+msg);
            if(msg.equals("bye")){
                break;
            }
        }
        is.close();
    }

}

遇到的問題:
我不知道有沒有人和我一樣在讀寫的時候用了BufferedReader和BufferedWriter,以至於在後面使用readLine()方法時儘管是多執行緒也一直處於阻塞狀態,我找了一下午,後來改成使用DataOutput/InputStream以及對應的readUTF()和writeUTF()方法,這個問題就解決了,具體原因我想了很久也沒想明白,有個猜測不確定,等下週問了老師得到準確的答案再來說吧!!!
立個Flag:接下來有時間的話自己再用nio實現一下非阻塞通訊,到時候來更博!