java socket系列文章
java socket 單線程echo服務(wù)器
java socket 多線程echo服務(wù)器
java socket 線程池echo服務(wù)器
簡單介紹socket
socket,通常也稱作"套接字",用于描述IP地址和端口,是網(wǎng)絡(luò)上運(yùn)行的兩個(gè)程序間雙向通訊的一端,它既可以接受請求,也可以發(fā)送請求,利用它可以較為方便的編寫網(wǎng)絡(luò)上的數(shù)據(jù)的傳遞。
Socket通訊過程:服務(wù)端監(jiān)聽某個(gè)端口是否有連接請求,客戶端向服務(wù)端發(fā)送連接請求,服務(wù)端收到連接請求向客戶端發(fā)出接收消息,這樣一個(gè)連接就建立起來了。客戶端和服務(wù)端都可以相互發(fā)送消息與對方進(jìn)行通訊。
socket編程中重要的方法:
- Accept方法用于產(chǎn)生”阻塞”,直到接受到一個(gè)連接,并且返回一個(gè)客戶端的Socket對象實(shí)例?!弊枞笔且粋€(gè)術(shù)語,它使程序運(yùn)行暫時(shí)”停留”在這個(gè)地方,直到一個(gè)會話產(chǎn)生,然后程序繼續(xù);通常”阻塞”是由循環(huán)產(chǎn)生的
- getInputStream方法獲得網(wǎng)絡(luò)連接輸入,即一個(gè)輸入流,同時(shí)返回一個(gè)IutputStream對象實(shí)例,客戶端的Socket對象上的 getInputStream方法得到的輸入流其實(shí)就是從服務(wù)器端發(fā)回的數(shù)據(jù)流;服務(wù)器端的輸入流就是接受客戶端發(fā)來的數(shù)據(jù)流。
- getOutputStream方法實(shí)現(xiàn)一個(gè)輸出流,同時(shí)返回一個(gè)OutputStream對象實(shí)例??蛻舳说妮敵隽骶褪菍⒁l(fā)送到服務(wù)器端的數(shù)據(jù)流,服務(wù)器端的輸出流就是發(fā)給客戶端的數(shù)據(jù)流。
注意:
- getInputStream和getOutputStream方法均會產(chǎn)生一個(gè)IOException,它必須被捕獲。
- getInputStream和getOutputStream方法返回的是流對象,通常都會被另一個(gè)流對象使用。所以還要對這兩種方法獲取的數(shù)據(jù)進(jìn)行封裝,以便更方便的使用。
如何開發(fā)一個(gè)Echo服務(wù)器
- 服務(wù)器,使用ServerSocket監(jiān)聽指定的端口,端口可以隨意指定(由于1024以下的端口通常屬于保留端口,在一些操作系統(tǒng)中不可以隨意使用,所以建議使用大于1024的端口),等待客戶連接請求,客戶連接后,會話產(chǎn)生;在完成會話后,關(guān)閉連接。
- 客戶端,使用Socket對網(wǎng)絡(luò)上某一個(gè)服務(wù)器的某一個(gè)端口發(fā)出連接請求,一旦連接成功,打開會話;會話完成后,關(guān)閉Socket。
服務(wù)器端代碼:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
public class server {
public static void main(String[] args) throws Exception{
ServerSocket server = new ServerSocket(20011);
//服務(wù)端在20011端口監(jiān)聽客戶端請求的TCP連接
Socket client = null;
boolean f = true;
while(f){
client = server.accept();
//服務(wù)端在調(diào)用accept()等待客戶端的連接請求時(shí)會阻塞,直到收到客戶端發(fā)送的連接請求才會繼續(xù)往下執(zhí)行代碼
//鏈接成功后為每個(gè)客戶端連接開始做出處理
try{
PrintStream out = new PrintStream(client.getOutputStream());
//獲取Socket的輸出流,用來向客戶端發(fā)送數(shù)據(jù)
BufferedReader buf = new BufferedReader(new InputStreamReader(client.getInputStream()));
//獲取Socket的輸入流,用來接收從客戶端發(fā)送過來的數(shù)據(jù)
boolean flag =true;
while(flag){
String str = buf.readLine();
//接收從客戶端發(fā)送過來的數(shù)據(jù)
if(str == null || "".equals(str)){
flag = false;
}else{
if("bye".equals(str)){
flag = false;
}else{
//將接收到的字符串前面加上echo,發(fā)送到對應(yīng)的客戶端
out.println("echo:" + str);
}
}
}
out.close();
client.close();
}catch(Exception e){
e.printStackTrace();
}
}
server.close();
}
}
這個(gè)程序建立了一個(gè)服務(wù)器,它一直監(jiān)聽20011端口,等待用戶連接。在建立連接后開始接受客戶端傳來的信息并再次將信息返回給客戶端,當(dāng)客戶端輸入“bye”時(shí),結(jié)束會話。這個(gè)程序一次只能接受一個(gè)客戶連接。
客戶端代碼:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
import java.net.SocketTimeoutException;
public class client {
public static void main(String[] args) throws IOException {
Socket client = new Socket("127.0.0.1", 20011);
//客戶端請求與本機(jī)在20011端口建立TCP連接
client.setSoTimeout(10000);
BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
//獲取鍵盤輸入
PrintStream out = new PrintStream(client.getOutputStream());
//獲取Socket的輸出流,用來發(fā)送數(shù)據(jù)到服務(wù)端
BufferedReader buf = new BufferedReader(new InputStreamReader(client.getInputStream()));
//獲取Socket的輸入流,用來接收從服務(wù)端發(fā)送過來的數(shù)據(jù)
boolean flag = true;
while(flag){
System.out.print("輸入信息:");
String str = input.readLine();
out.println(str);
//發(fā)送數(shù)據(jù)到服務(wù)端
if("bye".equals(str)){
flag = false;
}else{
try{
//從服務(wù)器端接收數(shù)據(jù)有個(gè)時(shí)間限制(系統(tǒng)自設(shè),也可以自己設(shè)置),超過了這個(gè)時(shí)間,便會拋出該異常
String echo = buf.readLine();
System.out.println(echo);
}catch(SocketTimeoutException e){
System.out.println("Time out, No response");
}
}
}
input.close();
if(client != null){
//如果構(gòu)造函數(shù)建立起了連接,則關(guān)閉套接字,如果沒有建立起連接,自然不用關(guān)閉
client.close(); //只關(guān)閉socket,其關(guān)聯(lián)的輸入輸出流也會被關(guān)閉
}
}
}
這個(gè)客戶端連接到地址為1270.0.1的服務(wù)器,端口為20011,并從鍵盤輸入一行信息,發(fā)送到服務(wù)器,然后接受服務(wù)器的返回信息。
Socket client = new Socket("127.0.0.1", 20011);
Socket實(shí)例代表了TCP連接的一個(gè)客戶端,客戶端請求與本機(jī)在20011端口建立TCP連接 ,127.0.0.1為IP地址。
client.setSoTimeout(10000);
表示如果對方連接狀態(tài)10秒沒有收到數(shù)據(jù)的話強(qiáng)制斷開客戶端。
BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
獲取鍵盤輸入。
InputStreamReader 將字節(jié)流轉(zhuǎn)換為字符流
BufferedReader,字符輸入流中讀取文本,緩沖各個(gè)字符,從而實(shí)現(xiàn)字符、數(shù)組和行的高效讀取。
最后,首先運(yùn)行server類,然后client類,然后在client的控制臺輸入任意字符,可以看到當(dāng)輸入bye是server和client都會退出。
運(yùn)行結(jié)果,如圖


此項(xiàng)目的完整代碼可以到我的github,java-socket進(jìn)行下載。