tcp/ip只是一個協(xié)議族的稱號,就是說一個家族的意思。它里面有各種協(xié)議惕橙,比如 ip協(xié)議、ftp協(xié)議钉跷、udp協(xié)議弥鹦。Java中為使用TCP協(xié)議提供了二個類 Socket和ServerSocket,一般的socket模式中爷辙,Serversocket只有一個彬坏,Socket而有
多個。
TCP連接建立步驟
客戶端和服務(wù)端建立連接后膝晾,就被動的等待服務(wù)器的響應(yīng)栓始。典型的TCP客戶端要經(jīng)過以下步驟。
客戶端
- 創(chuàng)建一個Socket實(shí)例血当,構(gòu)造函數(shù)指定遠(yuǎn)程主機(jī)的IP地址和端口號幻赚。
- 通過Socket的I/O流來和服務(wù)器進(jìn)行通信
- 使用Socket的close來關(guān)閉連接。
服務(wù)端
- 創(chuàng)建一個ServerSocket實(shí)例指定本地端口臊旭,監(jiān)聽客戶端在該端口發(fā)起的TCP請求
- 重新執(zhí)行accept方法來獲取客戶端的連接
- 為獲取的客戶端開啟一個新線程落恼,利用I/O流和客戶端進(jìn)行通信。通信完成調(diào)用客戶端的close方法關(guān)閉流离熏。
下面通過代碼來體現(xiàn)上面說的步驟
Socket
Socket就是一個客戶端佳谦,可以和ServerSocket建立起連接,建立連接后就可以和Server進(jìn)行通信了撤奸。創(chuàng)建一個Socket要指定IP地址和端口號吠昭。每個Socket都會關(guān)聯(lián)一個InputStream和OutPutSteram喊括,我們通過 把字節(jié)寫入套接字的OutOutStream來發(fā)送數(shù)據(jù),并且通過InputSrteam來接收數(shù)據(jù)矢棚。
public static void main(String[] args) throws IOException {
//客戶端請求與本機(jī)在20006端口建立TCP連接
Socket client = new Socket("127.0.0.1", 1217);
client.setSoTimeout(10000);
//獲取鍵盤輸入
BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
//獲取Socket的輸出流郑什,用來發(fā)送數(shù)據(jù)到服務(wù)端
PrintStream out = new PrintStream(client.getOutputStream());
//獲取Socket的輸入流,用來接收從服務(wù)端發(fā)送過來的數(shù)據(jù)
BufferedReader buf = new BufferedReader(new InputStreamReader(client.getInputStream()));
boolean flag = true;
while(flag){
System.out.print("輸入信息:");
String str = input.readLine();
//發(fā)送數(shù)據(jù)到服務(wù)端
out.println(str);
if("bye".equals(str)){
flag = false;
}else{
try{
//從服務(wù)器端接收數(shù)據(jù)有個時(shí)間限制(系統(tǒng)自設(shè)蒲肋,也可以自己設(shè)置)蘑拯,超過了這個時(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)閉
}
}
ServerSocket
服務(wù)端的工作就是建立一個通信端剃法,被動等待客戶端的連接請求。
public static void main(String[] args) throws Exception{
//開啟一個服務(wù)端路鹰,端口號1217
ServerSocket server = new ServerSocket(1217);
Socket client = null;
boolean f = true;
while(f){
System.out.println("服務(wù)開啟成功贷洲!");
//等待客戶端的連接,會一直等待晋柱。
client = server.accept();
System.out.println("與客戶端連接成功优构!");
//為每個客戶端連接開啟一個線程
new Thread(new ServerThread(client)).start();
}
server.close();
}
public static class ServerThread implements Runnable {
private Socket client = null;
public ServerThread(Socket client){
this.client = client;
}
@Override
public void run() {
try{
//獲取Socket的輸出流,用來向客戶端發(fā)送數(shù)據(jù)
PrintStream out = new PrintStream(client.getOutputStream());
//獲取Socket的輸入流雁竞,通過它來獲取客戶端發(fā)送的信息钦椭。
BufferedReader buf = new BufferedReader(new InputStreamReader(client.getInputStream()));
boolean flag =true;
while(flag){
//接收從客戶端發(fā)送過來的數(shù)據(jù)
String str = buf.readLine();
System.out.println(str);
if(str == null || "".equals(str)){
flag = false;
}else{
if("bye".equals(str)){
flag = false;
}else{
//將接收到的字符串前面加上echo,發(fā)送到對應(yīng)的客戶端
out.println("服務(wù)器收到了信息:" + str);
}
}
}
out.close();
client.close();
}catch(Exception e){
e.printStackTrace();
}
}
}