淺談java socket通信,並附源碼

最近做的一個項目中,涉及到socket通信部分很多。在查閱大量資料後發現資料對於我自己大多分兩種,過於理論或者代碼深度太深看不懂。總覺得缺少中間橋樑讓我平緩的過度。在觀看郭霖大哥(我要給你生猴子)的視頻講解後恍然大悟,將講解實例代碼敲了下來並適當做了註解。

關於socket的基礎知識網上很多很詳細,我就不做過多的講解,直接上代碼。

客戶端:

package socket;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;

public class Clientsocket {
	public static void main(String[]args){
		Clientsocket client=new Clientsocket();
		client.start();
		
	}
	public void start(){
		BufferedReader reader=null;
		BufferedReader read=null;
		BufferedWriter writer=null;
		Socket socket=null;
		try {
			reader=new BufferedReader(new InputStreamReader(System.in));
			String outputstring;
			socket=new Socket("127.0.0.1", 9898);
			read=new BufferedReader(new InputStreamReader(socket.getInputStream()));
			writer=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
			startServerListener(read);
			while(!(outputstring=reader.readLine()).equals("bye")){
				
				writer.write(outputstring+"\n");
				writer.flush();
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			try {
				read.close();
				writer.close();
				socket.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
	}
	/*
	 * 監聽功能,新開一個線程不影響主線程的運行,是客戶端能實時監聽來自服務器的數據
	 */
	public void startServerListener(final BufferedReader reader){
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				try {
					String response;
					while((response=reader.readLine())!=null){
						System.out.println(response);
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
				
				
			}
		}).start();
	}

}
服務器:

package SeeHtml;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Timer;
import java.util.TimerTask;


public class Server {
	BufferedWriter writer=null;
	BufferedReader reader=null;
	public static void main(String[]args){
		Server serversocket=new Server();
		serversocket.start();
	}
	public void start(){
		
		
		ServerSocket server=null;
		Socket socket=null;
		try {
			server=new ServerSocket(9898);
			while(true){
				socket=server.accept();
				/*
				 * 當沒有客戶端連接服務器時,accept方法會阻塞住
				 */
				System.out.println("client "+socket.hashCode()+"connect...");
				manageConnection(socket);
			}
			
			
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			try {
				socket.close();
				server.close();
				
			} catch (Exception e2) {
				e2.printStackTrace();
			}
		}
		
	}
	/*
	 * 連接管理
	 * 每次客戶端連接服務器是時都會生成一個socket,將socket傳入manage進行處理和發送
	 */
	public void manageConnection(final Socket socket){
		new Thread(new Runnable(){
			public void run(){
				String string=null;
				try {
					reader=new BufferedReader(new InputStreamReader(socket.getInputStream()));
					writer=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
					
					/*
					 * 下面爲測試代碼,爲了測試客戶端的監聽功能(客戶端接受服務器主動發送數據)是否成功,定時發送心跳包
					 * 由於在匿名類中使用,writer需要設置爲static或者全局變量
					 * new Timer().schedule(new TimerTask(){
						public void run(){
							try {
								writer.write("heart once...\n");
								writer.flush();
							} catch (IOException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
							
						}
					},3000, 3000);
					*/
					
					/*
					 * 注意:主線程中需要加入while形成循環,否子運行一次就會推出接受客戶端信息
					 * 同理,客戶端在寫消息的時候也需要注意這一點
					 */
					while(!(string=reader.readLine()).equals("bye")){
						System.out.println("client "+socket.hashCode()+":"+string);
						writer.write(string+"\n");
						writer.flush();
					}
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}finally{
					try {
						writer.close();
						reader.close();
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				
			}
		}).start();
	}

}
服務器跟客戶端的代碼中使用了很多循環和阻塞,爲的是防止出現一端已經斷開連接,另一端缺繼續寫入數據這種情況引發錯誤。

正如我上面所說,我們的代碼使用了很多阻塞循環和線程,使得在真正使用時會出現運行效率低,使用不方便等問題。但是java官方也考慮到此問題,在jdk1.4之後推出了java.nio。隨後有人對此又進行了封裝,得到了不少好用的框架,比如mina,可以學一學。

在此附上郭霖大哥的課程教學連接:

點擊打開鏈接http://www.imooc.com/learn/223



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章