摘要
TCP/IP協議族是構建互聯網的基石協議。在互聯網中,從一臺計算機向另外一臺計算機傳送數據,數據包可以通過兩種協議傳輸。其中一種就是傳輸控制協議(Transmission Control Protocol,TCP)。TCP能夠確保數據的傳送,也確保數據包以它們正確的順序傳送,是一種提供可靠連接的傳送協議。由於Java語言支持基於流的通信,即是用TCP協議進行傳輸,所以本次的課程設計將基於Java語言,設計出一個可以發送TCP數據包的程序。
關鍵字
傳輸控制協議(TCP),Java,套接字(Socket),IP,端口(Port)
1 引言
在互聯網的四層協議中,TCP位於IP層之上,應用層之下的傳輸層。不同主機的應用層之間經常需要可靠的、像管道一樣的連接。而面向連接、提供可靠傳輸的TCP協議則正好能夠滿足這一需求。因此被廣泛利用。
掌握TCP數據包的發包原理和功能的實現,有利於我們能夠更進一步地學習和利用更多應用層上的應用和技術,如文件傳送(FTP)、遠程登錄(RemoteLogin)等。
本次課程設計要求我們能夠實現以下效果:
(1) 以命令行形式運行:
SendTCP source_IP source_port dest_ip dest_port
其中,SendTCP爲程序名,source_IP爲源端IP地址,source_port爲源端口,dest_ip 爲目的IP地址,dest_port爲目的端口
(2) 其他的TCP頭部參數請自行設定。
(3) 數據字段爲“Thisis my homework of network ,I am happy!”.
(4) 成功發送後在屏幕上輸出“SendOK”。
2 總體設計
2.1 系統或算法框架設計
(1) 服務端的設計框架(發送數據段方)
2.2 功能設計
在本次課程設計中,要求發送一段數據包,裏面包含一段數據信息。同時,爲了驗證數據包發送成功,還需要進行驗證。因此需要實現至少發送數據包和驗證發送是否成功的兩項功能。建立服務端發送數據段,客戶端接收數據段併發送反饋信息。當它們分別運行在不同的主機上,運行程序。根據程序的運行情況,便能驗證這兩項功能。
在服務端,我們首先建立對源端口的監聽。當客戶端成功連接到源端口時,服務端即按要求發送數據段“This is my homework of network ,I amhappy!”到目的IP、端口。客戶端,新建端口的監聽,當收到數據段後發送“SendOK!”反饋給服務端。通過這樣的數據包傳送的數據,便能實現以上兩種功能,見圖3。要注意的是,服務端的源IP、端口即爲客戶端的目的IP、端口;服務端的目的IP、端口即爲客戶端的源IP、端口。
2.3 平臺設計
本次的課程設計在Java語言的平臺上利用Java語言實現。爲了實現在兩臺計算機發送數據包的功能。本次實驗採用了物理機和虛擬機模擬在同一個局域網中。其中物理機採用Windows 8.1系統,IP地址爲192.168.126.53,而虛擬機則採用Windows XP系統,IP地址爲192.168.126.52。如圖4所示。
2.4 數據結構的設計
本次實驗採用了String類型保存字符,而端口號則採用Int類型。而由於文本I/O需要編碼和解碼,所以,二進制I/O的效率比文本I/O的效率更高。因此最好使用二進制I/O在服務端和客戶端之間進行數據傳輸,以便提高效率。因此,在讀入和寫入分別採用了DataInputStream和DataOutStrea這兩個類。
3. 詳細設計(按照實際情況分小點,詳細書寫整個的設計流程以及核心源代碼)
3.1 參數讀入
不論是客戶端還是服務端,根據要求,都需要讀入IP和端口信息。而服務端的源IP、端口即爲客戶端的目的IP、端口;服務端的目的IP、端口即爲客戶端的源IP、端口。
- String sourceIP = args[0];//源IP
- int sourcePort = Integer.parseInt(args[1]);//源端口
- String destinationIP = args[2];//目的IP
- int destinationPort = Integer.parseInt(args[3]);//目的端口
String sourceIP = args[0];//源IP
int sourcePort = Integer.parseInt(args[1]);//源端口
String destinationIP = args[2];//目的IP
int destinationPort = Integer.parseInt(args[3]);//目的端口
3.2 建立套接字
無論是服務端還是客戶端都需要建立套接字(Socket)。建立套接字有兩種方法,一種是主動發送信息的。例外一種則是被動接收信息再發出反饋(監聽)。在本次課程實驗中,無論是兩端既需用到主動發信息又需要用到監聽。
- //主動發送信息,發送方向爲目的IP的目的端口
- Socket socket = new Socket(destinationIP, destinationPort);
- DataOutputStream dataOutputStream
- = new DataOutputStream(socket.getOutputStream());
- dataOutputStream.writeUTF("Response Please!");
- //監聽,接收發給源IP的源端口信息。
- ServerSocket serverSocket = new ServerSocket(sourcePort);
- socket = serverSocket.accept();
//主動發送信息,發送方向爲目的IP的目的端口
Socket socket = new Socket(destinationIP, destinationPort);
DataOutputStream dataOutputStream
= new DataOutputStream(socket.getOutputStream());
dataOutputStream.writeUTF("Response Please!");
//監聽,接收發給源IP的源端口信息。
ServerSocket serverSocket = new ServerSocket(sourcePort);
socket = serverSocket.accept();
3.3 發送或接收數據
作爲本次課程實驗的重點,發送和接收是否成功是本次課程設計是否成功的關鍵。爲了保證程序能夠成功運行,本次發送的數據均採用二進制數據流。
- //發送信息
- DataOutputStream dataOutputStream
- = new DataOutputStream(socket.getOutputStream());
- dataOutputStream.writeUTF("Response Please!");
- //接收信息
- DataInputStream dataInputStream
- = new DataInputStream(socket.getInputStream());
- String dataSegment=dataInputStream.readUTF();
//發送信息
DataOutputStream dataOutputStream
= new DataOutputStream(socket.getOutputStream());
dataOutputStream.writeUTF("Response Please!");
//接收信息
DataInputStream dataInputStream
= new DataInputStream(socket.getInputStream());
String dataSegment=dataInputStream.readUTF();
3.4 服務端功能實現
服務端在本次課程設計中,主要負責往目的套接字(目的IP+端口)發送數據段“Thisis my homework of network ,I am happy! ”,並接收來時目的套接字返回的數據段“SendOK!”,見圖6。
- //記錄源和目的套接字的信息
- String sourceIP = args[0];
- int sourcePort = Integer.parseInt(args[1]);
- String destinationIP = args[2];
- int destinationPort = Integer.parseInt(args[3]);
- //建立監聽
- ServerSocket serverSocket = new ServerSocket(sourcePort);
- Socket socket = serverSocket.accept();
- //接收來自客戶端的信息
- DataInputStream dataInputStream
- = new DataInputStream(socket.getInputStream());
- //發送信息
- String dataSegment = "This is my homework of network ,I am happy!";
- DataOutputStream dataOutputStream
- = new DataOutputStream(socket.getOutputStream());
- dataOutputStream.writeUTF(dataSegment);
- //接收成功信息
- socket = new Socket(destinationIP, destinationPort);
- dataOutputStream = new DataOutputStream(socket.getOutputStream());
- dataOutputStream.writeUTF("Successfully Received!");
- dataInputStream = new DataInputStream(socket.getInputStream());
- dataSegment=dataInputStream.readUTF();
- PrintMessage("接收到來自" + socket.getInetAddress().toString().substring(1) + ","
- + socket.getPort() + "號端口的信息");
- PrintMessage("信息內容爲:" + dataSegment);
- //關閉流
- dataInputStream.close();
- dataOutputStream.close();
- socket.close();
- serverSocket.close();
//記錄源和目的套接字的信息
String sourceIP = args[0];
int sourcePort = Integer.parseInt(args[1]);
String destinationIP = args[2];
int destinationPort = Integer.parseInt(args[3]);
//建立監聽
ServerSocket serverSocket = new ServerSocket(sourcePort);
Socket socket = serverSocket.accept();
//接收來自客戶端的信息
DataInputStream dataInputStream
= new DataInputStream(socket.getInputStream());
//發送信息
String dataSegment = "This is my homework of network ,I am happy!";
DataOutputStream dataOutputStream
= new DataOutputStream(socket.getOutputStream());
dataOutputStream.writeUTF(dataSegment);
//接收成功信息
socket = new Socket(destinationIP, destinationPort);
dataOutputStream = new DataOutputStream(socket.getOutputStream());
dataOutputStream.writeUTF("Successfully Received!");
dataInputStream = new DataInputStream(socket.getInputStream());
dataSegment=dataInputStream.readUTF();
PrintMessage("接收到來自" + socket.getInetAddress().toString().substring(1) + ","
+ socket.getPort() + "號端口的信息");
PrintMessage("信息內容爲:" + dataSegment);
//關閉流
dataInputStream.close();
dataOutputStream.close();
socket.close();
serverSocket.close();
3.5 客戶端功能實現
客戶端在本次課程設計中,主要負責的是接收來自服務端的信息,併發出反饋信息“Send OK!”,見圖7。
- //嘗試連接
- Socket socket = new Socket(destinationIP, destinationPort);
- DataOutputStream dataOutputStream
- = new DataOutputStream(socket.getOutputStream());
- dataOutputStream.writeUTF("Response Please!");
- //獲得迴應
- DataInputStream dataInputStream
- = new DataInputStream(socket.getInputStream());
- String dataSegment = dataInputStream.readUTF();
- PrintMessage("接收到來自" + socket.getInetAddress().toString().substring(1) + ","
- + socket.getPort() + "號端口的信息");
- PrintMessage("信息內容爲:" + dataSegment);
- //回覆
- ServerSocket serverSocket = new ServerSocket(sourcePort);
- socket = serverSocket.accept();
- dataOutputStream = new DataOutputStream(socket.getOutputStream());
- dataOutputStream.writeUTF("Send OK!");
//嘗試連接
Socket socket = new Socket(destinationIP, destinationPort);
DataOutputStream dataOutputStream
= new DataOutputStream(socket.getOutputStream());
dataOutputStream.writeUTF("Response Please!");
//獲得迴應
DataInputStream dataInputStream
= new DataInputStream(socket.getInputStream());
String dataSegment = dataInputStream.readUTF();
PrintMessage("接收到來自" + socket.getInetAddress().toString().substring(1) + ","
+ socket.getPort() + "號端口的信息");
PrintMessage("信息內容爲:" + dataSegment);
//回覆
ServerSocket serverSocket = new ServerSocket(sourcePort);
socket = serverSocket.accept();
dataOutputStream = new DataOutputStream(socket.getOutputStream());
dataOutputStream.writeUTF("Send OK!");
4 總結
4.2 存在的問題
(1) 命令行界面不夠美觀且操作性不夠強
(2) 每次都輸入4個參數太麻煩了
(1) 改用圖形界面,並美化界面。但可能速度上不夠現在的快。
(2) 仿照命令提示符(cmd),可以缺省輸入。
[1]Y.Daniel Liang.Java語言程序設計(基礎篇)[M].李娜,譯.北京:機械工業出版社,2011:527-535
[2]Y.Daniel Liang.Java語言程序設計(進階篇)[M].李娜,譯.北京:機械工業出版社,2011:258-264
[3]謝希仁.計算機網絡簡明教程(第二版)[M].北京:電子工業出版社,2013:123-143