黑马程序员 java基础之网络编程TCP
TCP網絡傳輸。
客戶端和服務端
?
分別對應著兩個對象。
Scoket(客戶端)和ServerSocket(服務端)。
?
? Socket(String ?address, int port)
????????? 創建一個流套接字并將其連接到指定 IP 地址的指定端口號。
這個客戶端在一建立的情況下就去連接服務端。
通過指定地址和指定的端口找到服務端。并與之建立連接。
?
步驟:
1.創建Socket服務,并指定要連接的主機和端口。
?? Socket s = new Socket("localhost",10002);
?? 如果上述這步成功了的話。也就是通路建立了。
當通路一建立,就有一個Socket流,也就是網絡流。
兩端之間建立了一個網絡流。Socket中既有輸入流也有輸出流,
一旦建立連接,在Socket中就可以取到輸入流和輸出流對數據進行操作。
?
流不用去建立,只要通路一建立,流就存在了。
?
getOutputStream()
?????????返回此套接字的輸出流。
getInputStream()
?????????返回此套接字的輸入流。
?
服務端
?
服務端沒有自己的流對象。
服務端和客戶端連接的時候,就使用了客戶端的流對象和客戶端進行操作。
?
public classTCPSocket {
?
????? /**
????? ?*@param args
????? ?*/
????? public static void main(String[] args)throws Exception
????? {
??????????
?????????? Socket s = newSocket("localhost",10002);
?????????? //為了發送數據,應該獲取socket流中的輸出流
?????????? OutputStream os =s.getOutputStream();
??????????
?????????? BufferedWriter bw = newBufferedWriter(new OutputStreamWriter(os));
?
?????????? bw.write("tcp,gemenwolaile");
?????????? bw.flush();
?????????? //而在這里不同去關流
?????????? s.close();
??????????
????? }
?
}
?
/*
?* 需求:定義端點接收數據并打印在控制臺上。
?* 服務端:
?* 1.建立服務端的Socket服務。通過ServerSocket類去建立。
?* 一旦建立,并監聽一個端口。
?* 2.獲取鏈接過來的客戶端對象。
?*?? 通過ServerSocket的accept方法去獲得。所以這個方法是阻塞式。
?* 3.客戶端如果發過來數據,那么服務端要使用對應的客戶端對象,并獲取到該客戶端
?* 的讀取流來讀取發過來的數據。并打印在控制臺。
?* 4.關閉服務端。(可選)
?*?
?* */
class TcpServer
{
????? public static void main(String[] args)throws Exception
????? {
??????????
?????????? //建立服務端Socket服務,并監聽一個端口。
?????????? ServerSocket ss? = new ServerSocket(10002);
?????????? //通過accept方法獲取連接過來的客戶端對象。
?????????? Socket s = ss.accept();
??????????
?????????? System.out.println(s.getInetAddress().getHostAddress());
?????????? //獲取客戶端發送過來的數據,那么要使用客戶端對象的讀取流方法來讀取數據。
??????????
?????????? InputStream in = s.getInputStream();
??????????
?????????? byte[] buf = new byte[1024];
??????????
?????????? int len = in.read(buf);
??????????
?????????? System.out.println(newString(buf,0,len));
??????????
?????
?????????? s.close();//關閉客戶端。
??????????
??????????
??????????
????? }
?????
?
}
?
必須先啟動服務端。
?
?
?
演示tcp傳輸的客戶端和服務端的互訪。
需求:客戶端給服務端發送數據,服務端收到后,給客戶端反饋信息。
?
/*
?1.建立socket服務。指定要連接的主機和端口
?2.獲取socket流中的輸出流,將數據寫到該流中。通過網絡發送給服務端。
?3.獲取socket流中的輸入流,將服務器反饋的數據獲取到,并打印。
?4.關閉客戶端資源。
?*/
?
class TcpClient2
{
????? public static void main(String[] args)throws Exception
????? {
?????????? Socket s =? new Socket("localhost",10004);
?????????? OutputStream os = s.getOutputStream();
?????????? os.write("nihao".getBytes());
??????????
?????????? InputStream is = s.getInputStream();
??????????
?????????? byte [] arr = new byte[1024];
?????????? //十分要主要,這里的read讀的是Socket流。也是一個阻塞式方法。只有服務端往回發送數據的時候,才會解除阻塞。
?????????? int len = is.read(arr);
??????????
?????????? System.out.println(newString(arr,0,len));
?????????? s.close();
?????
??????????
????? }
}
class TcpServer2
{
????? public static void main(String[] args)throws Exception
????? {
?????????? ServerSocket ss = newServerSocket(10004);
??????????
?????????? Socket s = ss.accept();
?????????? InputStream is = s.getInputStream();
??????????
?????????? byte [] arr = new byte[1024];
?????????? int len = is.read(arr);
??????????
?????????? System.out.println(newString(arr,0,len));
??????????
?????????? OutputStream os =s.getOutputStream();
?????????? os.write("完成".getBytes());
??????????
?????????? s.close();
??????????
??????????
??????????
??????????
????? }
}
?
?
?
?
package day5;
importjava.net.*;
importjava.io.*;
public classTCPSocket2 {
?
?????
????? public static void main(String[] args) {
?????????? // TODO Auto-generated method stub
?
????? }
?
}
?
?
class Client3
{
?
????? public static void main(String[] args)throws Exception
????? {
?????????? Socket s = newSocket("localhost",10009);
??????????
?????????? BufferedWriter bw = new BufferedWriter(newOutputStreamWriter(s.getOutputStream()));
??????????
?????????? BufferedReader br = newBufferedReader(new InputStreamReader(System.in));
?????????? String ss = null;
??????????
?????????? BufferedReader brr = newBufferedReader(new InputStreamReader(s.getInputStream()));
?????????? while((ss = br.readLine())!=null)
?????????? {
???????????????? bw.write(ss);
???????????????? bw.newLine();
???????????????? bw.flush();
????????????????
?????????? System.out.println(brr.readLine());
?????
?????????? }
??????????
??????????
?????????? br.close();
?????????? s.close();
??????????
????????????????
??????????
????? }
}
class Server3
{
?
????? public static void main(String[] args)throws Exception
????? {
?????????? ServerSocket ss = newServerSocket(10009);
??????????
?????????? Socket s = ss.accept();
?????????? InputStream is = s.getInputStream();
??????????
?????????? BufferedReader br = newBufferedReader(new InputStreamReader(is));
??????????
?????????? OutputStream os =s.getOutputStream();
?????????? BufferedWriter bw = new BufferedWriter(newOutputStreamWriter(os));
?????????? String sss? = null;
?????????? while((sss = br.readLine())!=null)
?????????? {
???????????????? //上邊的readLine只有在看到回車符后才能結束,也就是解除阻塞。
??????????
????????????????
??????????
?????????? bw.write(sss.toUpperCase());
?????????? bw.newLine();
?????????? bw.flush();
?????????? }
??????????
?????????? //有一個疑問,為什么當客戶端結束的時候,服務端也結束了,
?????????? //這是因為,當客戶端調用s.close()時,會在流里寫一個-1,
?????????? //然后服務器端就跳出循環,然后通過ss關閉服務器。
?????????? ss.close();
??????????
??????????
??????????
??????????
????? }
}
?
要注意,對于讀取流中的阻塞式方法來說,一定要將發送發的緩沖區刷新。
而且必須將行結束符寫到這個流中。
?
對于服務器端的阻塞式方法,如readLine(),必須在客戶端發送一個標志,讓服務器端知道其結束了,否則服務器一直處于讀取數據的狀態。
在客戶端使用
s.shutdownOutput();//關閉客戶端的輸出流,相當于給流中加入一個結束標記
?
?
下邊,我們使用更高級的協議去完成一個自定義瀏覽器和tomcat服務器的處理請求。
可以直接使用應用層的協議去封裝。
URL url = newURL("http://localhost:8080/GP2/index.jsp");
//首先將url地址封裝到一個對象為URL中。
URLConnectionconn = url.openConnection();
//這個URLConnection就封裝了有關底層協議的一些信息。
//也就通過一些應用層的協議進行拆包,并將這些屬性封裝到這個對象中去.
//然后通過openConnection()在內部幫助我們去完成Socket等一系列連接動作。
//所以不同寫Socket(是在傳輸層上的協議),而且是帶著協議去封裝的。
?
?
//當連接成功,當然可以將其服務端傳遞過來的數據拿到。也就是得到輸入流對象。
從獲取值
InputStream is =conn.getInputStream();
?
//從而從這個流對象中的得到值
byte [] arr =new byte[1024];
??????????
?????????? int len = 0;
?????????? while((len = is.read(arr))!=-1)
?????????? {
???????????????? System.out.println(newString(arr,0,len));
????????????????
?????????? }
?
這時候傳遞過來的數據就沒有了響應頭。而直接打出html中的信息。
這是因為。當底層的網絡協議把數據封裝好之后(包括響應頭),通過應用層去拆包之后,將數據和響應頭分離開來,得到的數據就只剩數據了。
而這些響應頭中的信息,可以通過URLConnection對象中的一系列方法進行簡析.
比如說:System.out.println(conn.getHeaderField("Server"));
可以得到有關服務器的信息。
當瀏覽器寫入一個網址之后,去訪問某一臺主機的時候.它到底做什么了事情?
?在上網的時候,先去本地找hosts中的各自域名的映射關系.
當本地有,就返回本地的,如localhost,如果本地沒有,就去各自運營商提供的域名服務器DNS中去尋找映射關系,最后使用ip地址找到對應的服務器,使用端口找到對應的應用程序.如果直接輸入ip地址,則不走域名簡析.
?
?
?
轉載于:https://www.cnblogs.com/xiewen3410/archive/2013/05/14/3078647.html
總結
以上是生活随笔為你收集整理的黑马程序员 java基础之网络编程TCP的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《Java多线程编程核心技术》读后感(十
- 下一篇: dot-- 资源汇总