java Socket編程

一.網絡通訊,常見的結構是C/S模式。客戶端在須要服務時向服務器請求鏈接,服務端被動接收鏈接,創建鏈接後,雙方開始通訊。服務器進程通常做爲守護進程,一直運行,不斷監聽網絡端口,被動接收客戶端的請求,當接收到客戶的請求時,會啓動一個服務進程來處理客戶的請求,並繼續監聽網絡端口。html

(上圖轉自:http://tutorials.jenkov.com/java-networking/index.htmljava

二.網絡上進程之間經過雙向的通訊鏈接來實現信息的交換。這樣鏈接的一端稱爲一個Socket。Socket由IP號和端口號肯定。在java中使用Socket來實現基於TCP/IP協議的網絡程序,主要涉及到下面幾步:服務器

客戶端:網絡

1.根據服務器的IP和端口號,創建Socketsocket

2.打開輸入、輸出流this

3.對Socket進行讀寫spa

4.關閉輸入、輸出流,關閉套接字.net

服務器端:線程

1.根據端口號創建ServerSocketcode

2.被動監聽客戶端請求

3.當監聽到客戶端請求時,接收請求,啓動工做線程,處理請求。若再也不接收請求時,進入4;不然,繼續監聽,轉2

4.關閉ServerSocket

下面以例子來講明:

客戶端代碼:

package com.net.examples;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
public class Client {

    /**
     * @param args
     * @throws IOException 
     * @throws UnknownHostException 
     * @throws InterruptedException 
     */
    public static void main(String[] args) throws UnknownHostException, 
        IOException, InterruptedException {
        //這裏假設有三個client,每一個client分別發送一次請求
        int clientCount = 3;
        MyRunable run = new MyRunable();
        while(clientCount > 0){
            //每一個線程模擬一個client,三個線程名分別爲1,2,3
            new Thread(run,clientCount+"").start();
            clientCount--;
        }
    }
}

//定義MyRunable,重寫run方法實現client線程
class MyRunable implements Runnable{
    public void run() {
        int messCount = 2;
        Socket socket = null;
        DataOutputStream o = null;
        DataInputStream in = null;
        try {
            //1.建立Socket,創建鏈接
            socket = new Socket("127.0.0.1",8080);
            //2.打開輸入輸出流
            o = new DataOutputStream(socket.getOutputStream());
            in = new DataInputStream(socket.getInputStream());
            System.out.println("Clients begin send messages");
                //每一個client對Socket寫兩次
            while(messCount > 0 ){
                try {
                    //3.對Socket進行寫
                    o.writeUTF("" + messCount);
                    o.flush();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                System.out.println("I am client:"+Thread.currentThread().getName() +",I send message:" + messCount);
                messCount--;
            }
            //對Socket進行讀
            System.out.println("I am client:" + Thread.currentThread().getName() + ",and server "+ in.readUTF() + "(me!)");
        } catch (IOException e2) {
            e2.printStackTrace();
        } finally{
            try {
                //4.關閉輸入輸出流,關閉socket,釋放資源
                o.close();
                in.close();
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

服務端代碼:

package com.net.examples;

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

//Server
public class Server {
    private static int clientCount = 3;
    //Server線程結束運行條件,這裏是假設知道一共會收到三次客戶端請求
    private static boolean isStop(){
        return clientCount == 0 ? true:false;
    }
    public static void main(String[] args) throws IOException, InterruptedException {
        //1.創建ServerSocket
        ServerSocket serverSocket = new ServerSocket(8080);
        //2.監聽客戶端請求
        while(!isStop()){
            //3.接收到客戶端請求,並啓動一個線程處理
            Socket client = serverSocket.accept();
            new MyThread(client,clientCount).start();
            clientCount--;
        }
        //4.關閉ServerSocket
        serverSocket.close();
    }
}
//客戶端請求處理線程
class MyThread extends Thread{
    private Socket clientSocket;
    private int id;
    private DataInputStream input;
    private DataOutputStream output ;
    public MyThread (){
    }
    public MyThread(Socket soc,int i){
        this.clientSocket = soc;
        this.id = i;
    }
    public void run(){
        try {
            //得到輸入輸出流
            input = new DataInputStream((clientSocket.getInputStream()));
            output = new DataOutputStream(clientSocket.getOutputStream());
            int count = 2;
            //讀取Socket
            while(count > 0){
                System.out.println("I am server.I have received message:" + input.readUTF() + ",from" + id);
                count --;
            }
            //寫Socket
            output.writeUTF("respose to client" + id);
            output.flush();;
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                //釋放資源,關閉鏈接
                input.close();
                output.close();
                clientSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

運行結果以下:

client:

Server:

 

不過,後來我稍微地改了下Client.java文件中MyRunable.java,輸出流o,在對Socket寫完以後,就調用了o.close()方法,而不是在讀完Socket後釋放掉,從新跑程序後client跑的就有錯出現了,Server程序沒出錯。具體如改動下紅色的部分,而報錯也以下圖:

個人理解是,輸出流不用了,因此就close()了,爲何在讀Socket時(58行的代碼),會報socket closed這樣的出錯信息。難道調用o.close()時,會關閉socket??或者是其餘緣由,實在不理解,剛剛看着java Socket這一塊,好多不清楚。麻煩看到的童鞋幫解答下。。。

相關文章
相關標籤/搜索