天天看點

JAVA網絡程式設計(Socket)

       在Java中,基于TCP協定實作的網絡通信類有兩個:Socket類和ServerSocket類,用戶端使用的是Socket類,伺服器端使用的是ServerSocket類。使用它們可以友善的完成資訊的互動,用戶端與伺服器端的連接配接,由伺服器端向用戶端提供服務。

       Socket類建立連接配接的過程是:首先在伺服器端指定一個用來等待連接配接的端口建立一個ServerSocket執行個體,然後在用戶端通過規定一個主機與端口号建立一個Socket執行個體,連接配接到伺服器上。ServerSocket類的accept方法使伺服器處于阻塞狀态,等待使用者請求。

       Scoket通信程式基本過程(4個步驟):

     (1).在用戶端和伺服器端建立Scoket/ServerSocket執行個體。

     (2).打開連接配接到Socket的輸入/輸出流。

     (3).利用輸入/輸出流和Socket。

     (4)關閉Socket(I/O流是基于Socket管道的,當Socket關閉時,I/O流也随之關閉)。

       Socket連接配接過程如下圖所示:

JAVA網絡程式設計(Socket)

1.建立Socke連接配接

主要實作代碼:

服務端:

try{
     ServerSocket server  = new ServerSocket(9000);//伺服器端建立套接字服務
}
catch(IOException e){
     //
}
Socket socket = null;
try{
     socket = server.accept();//監聽用戶端連接配接
}
catch(IOException e){
   //
}
           

用戶端:

try{
    Socket client = new Socket(host,9000);//用戶端建立套接字
}
catch(IOException e){
   //
}
           

2.在用戶端和伺服器端同時打開輸入/輸出流

       Socket 提供方法getinputStream()和getOutputStream()來得到對應的輸入/輸出流,進行資料的讀寫操作,方法分别傳回InputStream對象和OutpputStream對象。可以把它們封裝在緩沖流中以提高程式的性能,主要代碼如下所示:

//輸入流
InputStreamReader isr = new InputStreamReader(socket.getInputStream());
BufferedReader br = new BufferedReader(isr);
//輸出流
InputStreamWriter isw = new InputStreamWriter(socket.getOutputStream());
InputStreamReader isr = new InputStreamReader(isw);
           

3.關閉輸入/輸出流

       在用戶端和伺服器端關閉Socket.

範例示範:

       建立一個簡單的聊天程式為例示範Socket程式設計,該程式分為用戶端和伺服器端。伺服器端能夠接收到多個連接配接,用戶端可以連接配接伺服器,發送資訊給伺服器端,伺服器接受消息,轉發給所有客戶。

實作結果如下圖所示:

JAVA網絡程式設計(Socket)

實作代碼:

伺服器端代碼:

server.java

package com.venus.myscoket.server;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Enumeration;
import java.util.Vector;

public class Server {
    
    public Server(int port) throws Exception {//構造函數,參數為端口号
        //建立ServerSocket
        ServerSocket server = new ServerSocket(port);
        //不斷接受客戶資訊
        while(true){
            //監聽用戶端的連接配接
            Socket conn = server.accept();
            //将伺服器端的輸入流封裝到DataInputStream類中,該類支援與機器無關的編碼方式
            DataInputStream in = new DataInputStream(conn.getInputStream());
            //讀取使用者資訊
            String who = in.readUTF();
            System.out.println("Client+(Ip:"+conn.getInetAddress()+")"+who+"enter!"+"\n");
            
            //每次監聽就建立一個線程
            ServerHander cn = new ServerHander(who,conn);
            
            cn.start();
        }
    }
    public static void main(String args[]) throws Exception{
        new Server(9013);
    }

}
class ServerHander extends Thread{
    Socket socket = null;
    DataInputStream in = null;
    DataOutputStream out = null;
    String who = null;
    //保護所有的用戶端對象
    protected static Vector<ServerHander>clientlist = new Vector<ServerHander>();
    public ServerHander(String name,Socket socket) throws IOException {
        this.who = name;
        this.socket = socket;
        
        in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
        out = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
    }
    @Override
    public void run() {
        try {
        clientlist.addElement(this);
        sendallclient("weclome  "+who+"  entered");
        //無限循環
            while(true){
                String msg = in.readUTF();
                sendallclient(who+" : "+msg);
                }
                

            } catch (IOException e) {
                System.out.println("client exit or error.");
            }finally{
                clientlist.removeElement(this);
                sendallclient(who+"left !");
                try {
                    socket.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    System.out.println("Connection has been closed");
                }
            }
            
    }
/**
 * 給用戶端傳遞資訊的方法
 * @param msg
 */
protected static void sendallclient(String msg){
    synchronized (clientlist) {//對用戶端的vector加鎖
        Enumeration<ServerHander> allclients = clientlist.elements();
        //周遊通路每個用戶端對象
        while(allclients.hasMoreElements()){
            
            ServerHander serh = (ServerHander)allclients.nextElement();
            try {
                serh.out.writeUTF(msg);//向用戶端發送資訊
                serh.out.flush();//重新整理輸出流,保證内容輸出
            } catch (IOException e) {
                // TODO Auto-generated catch block
                serh.interrupt();//終端線程
            }
            }
        }
    }
}


           

用戶端代碼:

Client.java

package com.venus.myscoket.server;

import java.awt.BorderLayout;
import java.awt.Frame;
import java.awt.TextArea;
import java.awt.TextField;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;


public class Client {
	public ServiceFrame sf;//用戶端窗體
	private Socket csocket;//Socket對象
	private DataInputStream in;//輸入流
	private DataOutputStream out;//輸出流
	public static void main(String[] args){
		String who="";
		//獲得輸出流
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
		//輸出提示資訊
		System.out.print("please input your name,and then please Enter :");
		try {
			//讀取登入名
			who =  in.readLine().trim();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		//調用Client構造函數
		new Client(who,"172.20.83.37",9013);
	} 
	

public Client(String who,String server,int port){
		//建立用戶端窗體
		sf = new ServiceFrame("簡單聊天");
		//添加鍵盤監聽事件
		sf.sendFD.addKeyListener(new ActListener(this, sf));
		sf.addWindowListener(new ExitListener(this));
		try {
				//建立Socket對象
				csocket = new Socket(server ,port);
				//輸入流
				in = new DataInputStream(new BufferedInputStream(csocket.getInputStream()));
				//輸出流
				out = new DataOutputStream(new BufferedOutputStream(csocket.getOutputStream()));
				//向輸出流輸出who資訊
				out.writeUTF(who);
				//重新整理輸出流
				out.flush();
			
			while(true){
				sf.showTA.append("--"+in.readUTF()+"\n");//在窗體輸出資訊
			}
			} catch (Exception e) {
				System.out.println("Server error!");
				this.close();
				System.exit(0);
			} 		
}


protected void send(String msg){//輸出資訊
	try {
		out.writeUTF(msg);
		out.flush();
	} catch (IOException e) {}
	}
protected void close(){
	try {
		sf.dispose();
	
		out.close();
		in.close();
		csocket.close();
	} catch (IOException e) {}
}
}

class ServiceFrame extends Frame{
	protected TextArea showTA;
	protected TextField sendFD;
	public ServiceFrame(String winnm){
		super(winnm);
		setLayout(new BorderLayout());
		add("North",showTA = new TextArea());
		showTA.setEditable(false);
		add("South",sendFD = new TextField());
		pack();
		show();
		sendFD.requestFocus();
	}
}
class ActListener extends KeyAdapter{
	Client client;
	ServiceFrame sFrame;
	public ActListener(Client c,ServiceFrame sf) {
		client = c;
		sFrame = sf;
	}
	public void keyPressed(KeyEvent e){
		if(e.getKeyCode() == KeyEvent.VK_ENTER){
			client.send(sFrame.sendFD.getText());
			sFrame.sendFD.setText("");
		}
		
	}
}
class ExitListener extends WindowAdapter{
	Client client;
	public ExitListener(Client c){
		client = c;
	}
	public void windowClosing(WindowEvent e){
		client.close();
		System.exit(0);
	}
}