最近做的一個項目中,涉及到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