網絡編程——設計一個發送TCP數據包的程序

摘要

        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.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這兩個類。

2.5 接口設計

        根據題目要求,程序運行時必須輸入4個參數:源IP、源端口、目的IP、目的端口。程序開始時會判斷是否已經輸入了4個參數,如果沒有輸入四個參數,或輸入錯誤,輸出錯誤提示,如圖5所示。


3. 詳細設計(按照實際情況分小點,詳細書寫整個的設計流程以及核心源代碼)

3.1 參數讀入

         不論是客戶端還是服務端,根據要求,都需要讀入IP和端口信息。而服務端的源IP、端口即爲客戶端的目的IP、端口;服務端的目的IP、端口即爲客戶端的源IP、端口。

  1. String sourceIP = args[0];//源IP  
  2.     int sourcePort = Integer.parseInt(args[1]);//源端口  
  3.     String destinationIP = args[2];//目的IP  
  4.     int destinationPort = Integer.parseInt(args[3]);//目的端口  
save_snippets.png
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)。建立套接字有兩種方法,一種是主動發送信息的。例外一種則是被動接收信息再發出反饋(監聽)。在本次課程實驗中,無論是兩端既需用到主動發信息又需要用到監聽。

  1. //主動發送信息,發送方向爲目的IP的目的端口  
  2. Socket socket = new Socket(destinationIP, destinationPort);  
  3. DataOutputStream dataOutputStream   
  4. new DataOutputStream(socket.getOutputStream());  
  5. dataOutputStream.writeUTF("Response Please!");  
  6. //監聽,接收發給源IP的源端口信息。  
  7. ServerSocket serverSocket = new ServerSocket(sourcePort);  
  8.     socket = serverSocket.accept();  
save_snippets.png
//主動發送信息,發送方向爲目的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 發送或接收數據

         作爲本次課程實驗的重點,發送和接收是否成功是本次課程設計是否成功的關鍵。爲了保證程序能夠成功運行,本次發送的數據均採用二進制數據流。

  1.     //發送信息  
  2. DataOutputStream dataOutputStream   
  3. new DataOutputStream(socket.getOutputStream());  
  4. dataOutputStream.writeUTF("Response Please!");   
  5. //接收信息  
  6. DataInputStream dataInputStream  
  7.                         = new DataInputStream(socket.getInputStream());  
  8.                 String dataSegment=dataInputStream.readUTF();  
save_snippets.png
	//發送信息
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。

  1. //記錄源和目的套接字的信息  
  2. String sourceIP = args[0];  
  3. int sourcePort = Integer.parseInt(args[1]);  
  4. String destinationIP = args[2];  
  5. int destinationPort = Integer.parseInt(args[3]);  
  6.   
  7. //建立監聽  
  8. ServerSocket serverSocket = new ServerSocket(sourcePort);  
  9. Socket socket = serverSocket.accept();  
  10.   
  11. //接收來自客戶端的信息  
  12. DataInputStream dataInputStream  
  13.                         = new DataInputStream(socket.getInputStream());  
  14. //發送信息  
  15. String dataSegment = "This is my homework of network ,I am happy!";  
  16. DataOutputStream dataOutputStream   
  17. new DataOutputStream(socket.getOutputStream());   
  18. dataOutputStream.writeUTF(dataSegment);  
  19.                  
  20. //接收成功信息  
  21. socket = new Socket(destinationIP, destinationPort);  
  22. dataOutputStream = new DataOutputStream(socket.getOutputStream());  
  23. dataOutputStream.writeUTF("Successfully Received!");  
  24.   
  25. dataInputStream = new DataInputStream(socket.getInputStream());  
  26. dataSegment=dataInputStream.readUTF();  
  27. PrintMessage("接收到來自" + socket.getInetAddress().toString().substring(1) + ","  
  28.                         + socket.getPort() + "號端口的信息");  
  29. PrintMessage("信息內容爲:" + dataSegment);  
  30.   
  31. //關閉流  
  32. dataInputStream.close();  
  33. dataOutputStream.close();  
  34. socket.close();  
  35. serverSocket.close();  
save_snippets.png
//記錄源和目的套接字的信息
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。


  1.     //嘗試連接  
  2.         Socket socket = new Socket(destinationIP, destinationPort);  
  3.         DataOutputStream dataOutputStream   
  4. new DataOutputStream(socket.getOutputStream());  
  5.         dataOutputStream.writeUTF("Response Please!");  
  6.   
  7.    //獲得迴應  
  8. DataInputStream dataInputStream  
  9. new DataInputStream(socket.getInputStream());  
  10. String dataSegment = dataInputStream.readUTF();  
  11. PrintMessage("接收到來自" + socket.getInetAddress().toString().substring(1) + ","  
  12.                         + socket.getPort() + "號端口的信息");  
  13.         PrintMessage("信息內容爲:" + dataSegment);  
  14.   
  15. //回覆  
  16. ServerSocket serverSocket = new ServerSocket(sourcePort);  
  17. socket = serverSocket.accept();  
  18. dataOutputStream = new DataOutputStream(socket.getOutputStream());  
  19. dataOutputStream.writeUTF("Send OK!");  
save_snippets.png
	//嘗試連接
   		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個參數太麻煩了

4.3 改進的方法

(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







發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章