Bài số 2: Xây dựng ứng dụng Intranet với TCP Socket

Xây dựng chương trình server nghe ở một cổng TCP nào đó và đợi client kết nối đến để thực hiện trao đổi dữ liệu theo mô hình client/server. Các bước thực hiện như sau:

  • Bước 1: Xây dựng các chương trình server và client
  • Bước 2: Copy các chương trình vào các máy ảo CentOS
  • Bước 3: Cài đặt công cụ tcpdump
  • Bước 4: Thực hiện kết nối client/server và phân tích gói tin với tcpdump

Bước 1: Xây dựng các chương trình server và client

Chương trình phía server như sau:

import java.io.*;
import java.net.*;

public class tcpserver {

	public static void main(String[] args) throws Exception {
		String clientSentence; String capitalizedSentence;
		int tcp_port = 0;
		
		if (args.length !=1) {
			System.out.println("Usage: tcpserver [tcp port]");
			System.exit(0);
		}
		try {
			tcp_port = Integer.parseInt(args[0]);
		} catch (Exception e) {
			System.out.println("Usage: tcpserver [tcp port]");
			System.exit(0);
		}
		
		ServerSocket welcomeSocket = new ServerSocket(tcp_port);
		while(true) {
			System.out.println("TCP Server is listening for client connect at port: " + tcp_port);
			Socket connectionSocket = welcomeSocket.accept();
			connectionSocket.
			System.out.println("  - Got client connect from: " + 
					connectionSocket.getInetAddress().getHostAddress() + ":"  + connectionSocket.getPort());
			BufferedReader inFromClient = new BufferedReader(
					new InputStreamReader(connectionSocket.getInputStream()));
			DataOutputStream outToClient = new DataOutputStream(connectionSocket.getOutputStream());
			clientSentence = inFromClient.readLine();
			System.out.println("  - Received from client: " + clientSentence);
			System.out.println("  - Send to client: " + clientSentence.toUpperCase());
			capitalizedSentence = clientSentence.toUpperCase() + '\n';
			outToClient.writeBytes(capitalizedSentence);
			System.out.println("  - Finish working with client.\n\n");
		}
	}
}
			 

Chương trình phía client như sau:

import java.io.*;
import java.net.*;

public class tcpclient {

	public static void main(String[] args) throws Exception {
		String sentence; String modifiedSentence;
		int server_port = 0;
		String server_ip = "";
		Socket clientSocket = null;
		
		if (args.length !=2) {
			System.out.println("Usage: tcpclient [server address] [server port]");
			System.exit(0);
		}
		try {
			server_port = Integer.parseInt(args[1]);
			server_ip = args[0];
		} catch (Exception e) {
			System.out.println("Usage: tcpclient [server address] [server port]");
			System.exit(0);
		}
		
		try {
			System.out.println("Connecting to TCP Server at: [" + server_ip + ":" + server_port + "]");
			clientSocket = new Socket(server_ip, server_port);
		} catch (Exception e) {
			System.out.println("Cannot connect to TCP Server.\n” + 
								“Please check the server and run tcpclient again.");
			System.exit(0);
		}
		
		System.out.println("Server connected. Local client port: " + clientSocket.getLocalPort());
		BufferedReader inFromUser = new BufferedReader(new InputStreamReader(System.in));
		DataOutputStream outToServer = new DataOutputStream(clientSocket.getOutputStream());
		BufferedReader inFromServer = new BufferedReader(
									new InputStreamReader(clientSocket.getInputStream()));
		System.out.print("Enter a sentence to send to server: ");
		sentence = inFromUser.readLine();
		outToServer.writeBytes(sentence + '\n');
		modifiedSentence = inFromServer.readLine();
		System.out.println("Received from server: " + modifiedSentence);
		clientSocket.close(); 
	}
}
			 

Bước 2: Copy các chương trình vào các máy ảo CentOS

Có thể sử dụng Eclipse để soạn mã nguồn và dịch ra file class trên máy Windows. Chú ý phiên bản Java trên các máy CentOS là 1.5 nên khi dịch mã nguồn Java sang file class, cần sử dụng đúng phiên bản Java 1.5. Sau khi có các file class thì đưa lên các máy ảo CentOS để chạy. Phương pháp thư mục chia sẻ (share folder) có thể sử dụng để copy file giữa máy Windows và các máy CentOS rất đơn giản. Các bước thực hiện như sau.
Cài đặt Samba trên máy CentOS. Samba là thư viện trên Linux cho phép đọc các thư mục chia sẻ trên mạng từ máy Windows:

> yum install samba-client samba-common cifs-utils
Loaded plugins: fastestmirror
Setting up Install Process
Loading mirror speeds from cached hostfile
* base: centos-hn.viettelidc.com.vn
* extras: centos-hn.viettelidc.com.vn
* updates: centos-hn.viettelidc.com.vn
base                                                     | 3.7 kB     00:00
extras                                                   | 2.9 kB     00:00
updates                                                  | 3.4 kB     00:00
Package samba-client-3.6.23-21.el6_7.x86_64 already installed and latest version
Package samba-common-3.6.23-21.el6_7.x86_64 already installed and latest version
Package cifs-utils-4.8.1-20.el6.x86_64 already installed and latest version

Trên máy chủ Windows, tạo thư mục và share với quyền người sử dụng là username=centos/password=centos. Kiểm tra địa chỉ IP của card mạng VirtualBox Host-Only (thường là có địa chỉ 192.168.56.1) và thiết lập thư mục mount trong file config /etc/fstab trên máy ảo CentOS:

> nano /etc/fstab
\\192.168.56.1\share    /mnt/share      cifs    user,uid=500,suid,username=centos,password=centos 0 0

Các thư mục mount trong file fstab sẽ được tự động mount khi khởi động CentOS. Có thể yêu cầu CentOS thực hiện mount một thư mục đã được định nghĩa trong file cấu hình mà không cần khởi động lại máy với lệnh mount:

> mount /mnt/share

Nếu thành công, thư mục share của Windows sẽ được mount tại vị trí /mnt/share trên máy CentOS. Các file class sau khi được dịch trên Windows có thể đưa vào thư mục share này và sử dụng chúng trên CentOS tại thư mục /mnt/share.

Bước 3: Cài đặt công cụ tcpdump

Công việc tiếp theo là cài đặt tcpdump bằng yum. Đây là phần mềm bắt gói tin tầng Transport tại một card mạng. Chú ý tcpdump sử dụng thư viện libpcap nên cần cài đặt (hoặc update) cả hai phần mềm này. Bản CentOS minimal có lỗi với hai phần mềm này nên cần gỡ chúng khỏi CentOS trước rồi cài lại:

> yum remove tcpdump libpcap
Loaded plugins: fastestmirror
Setting up Remove Process
Resolving Dependencies
--> Running transaction check
---> Package libpcap.x86_64 14:1.4.0-4.20130826git2dbcaa1.el6 will be erased
---> Package tcpdump.x86_64 14:4.0.0-5.20090921gitdf3cb4.2.el6 will be erased
--> Finished Dependency Resolution

Dependencies Resolved

===========================================================================
Package    Arch      Version                               Repository                                                          Size
===========================================================================
Removing:
libpcap    x86_64    14:1.4.0-4.20130826git2dbcaa1.el6     @base    307 k
tcpdump    x86_64    14:4.0.0-5.20090921gitdf3cb4.2.el6    @base    818 k

Transaction Summary
===========================================================================
Remove        2 Package(s)

Installed size: 1.1 M
Is this ok [y/N]: y
Downloading Packages:
Running rpm_check_debug
Running Transaction Test
Transaction Test Succeeded
Running Transaction
Erasing    : 14:tcpdump-4.0.0-5.20090921gitdf3cb4.2.el6.x86_64       1/2
Erasing    : 14:libpcap-1.4.0-4.20130826git2dbcaa1.el6.x86_64        2/2
Verifying  : 14:libpcap-1.4.0-4.20130826git2dbcaa1.el6.x86_64        1/2
Verifying  : 14:tcpdump-4.0.0-5.20090921gitdf3cb4.2.el6.x86_64       2/2

Removed:
libpcap.x86_64 14:1.4.0-4.20130826git2dbcaa1.el6
tcpdump.x86_64 14:4.0.0-5.20090921gitdf3cb4.2.el6

Complete!

> yum install tcpdump libpcap
Loaded plugins: fastestmirror
Setting up Install Process
Loading mirror speeds from cached hostfile
* base: centos-hn.viettelidc.com.vn
* extras: centos-hn.viettelidc.com.vn
* updates: centos-hn.viettelidc.com.vn
Resolving Dependencies
--> Running transaction check
---> Package libpcap.x86_64 14:1.4.0-4.20130826git2dbcaa1.el6 will be installed
---> Package tcpdump.x86_64 14:4.0.0-5.20090921gitdf3cb4.2.el6 will be installed
--> Finished Dependency Resolution

Dependencies Resolved

===========================================================================
Package    Arch      Version                                Repository                                                        Size
===========================================================================
Installing:
libpcap    x86_64    14:1.4.0-4.20130826git2dbcaa1.el6      base    131 k
tcpdump    x86_64    14:4.0.0-5.20090921gitdf3cb4.2.el6     base    338 k

Transaction Summary
===========================================================================
Install       2 Package(s)

Total download size: 469 k
Installed size: 1.1 M
Is this ok [y/N]: y
Downloading Packages:
(1/2): libpcap-1.4.0-4.20130826git2dbcaa1.el6.x86_6 | 131 kB     00:00
(2/2): tcpdump-4.0.0-5.20090921gitdf3cb4.2.el6.x86_ | 338 kB     00:00
---------------------------------------------------------------------------
Total                                       75 kB/s | 469 kB     00:06
Running rpm_check_debug
Running Transaction Test
Transaction Test Succeeded
Running Transaction
Installing : 14:libpcap-1.4.0-4.20130826git2dbcaa1.el6.x86_64        1/2
Installing : 14:tcpdump-4.0.0-5.20090921gitdf3cb4.2.el6.x86_64       2/2
Verifying  : 14:libpcap-1.4.0-4.20130826git2dbcaa1.el6.x86_64        1/2
Verifying  : 14:tcpdump-4.0.0-5.20090921gitdf3cb4.2.el6.x86_64       2/2

Installed:
libpcap.x86_64 14:1.4.0-4.20130826git2dbcaa1.el6
tcpdump.x86_64 14:4.0.0-5.20090921gitdf3cb4.2.el6

Complete!

Bước 4: Thực hiện kết nối client/server và phân tích gói tin với tcpdump

Sử dụng hệ thống mạng của bài thực hành trong chương 1, trên máy R4 chạy tcpserver, trên máy R1 chạy tcpclient. Kết quả chạy trên R1 như bên dưới:

> cd /mnt/share/
> java tcpclient 192.168.4.2 6789
Connecting to TCP Server at: [192.168.4.2:6789]
Server connected. Local client port: 40776
Enter a sentence to send to server: test from router r1
Received from server: TEST FROM ROUTER R1

Kết quả chạy tcpserver trên R4:

> java tcpserver 6789
TCP Server is listening for client connect at port: 6789
- Got client connect from: 192.168.2.1:40776
- Received from client: test from router r1
- Send to client: TEST FROM ROUTER R1
- Finish working with client.

Trên máy R1, chạy lệnh tcpdump để hiển thị các gói tin TCP trong phiên truyền thông nói trên:

> tcpdump -X -i eth1 port 6789
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth1, link-type EN10MB (Ethernet), capture size 65535 bytes
1.	22:08:49.547334 IP 192.168.2.1.40776 > 192.168.4.2.6789: Flags [S], seq 823787201, win 14600, options [mss 1460,sackOK,TS val 5755656 ecr 0,nop,wscale 6], length 0
        0x0000:  4500 003c 2dc9 4000 4006 1b3d c0a8 3864  		E..<-.@.@..=..8d
        0x0010:  c0a8 3801 8f9b 1a85 3119 fec1 0000 0000  		.8.....1.......
        0x0020:  a002 3908 6fe7 0000 0204 05b4 0402 080a  		..9.o...........
        0x0030:  0057 d308 0000 0000 0103 0306           		.W..........
2.	22:08:49.547749 IP 192.168.4.2.6789 > 192.168.2.1.40776: Flags [S.], seq 1879460457, ack 823787202, win 8192, options [mss 1460,nop,wscale 8,sackOK,TS val 4548021 ecr 5755656], length 0
        0x0000:  4500 003c 601f 4000 8006 a8e6 c0a8 3801  		E..<`.@.......8.
        0x0010:  c0a8 3864 1a85 8f9b 7006 4a69 3119 fec2  		..8d....p.Ji1...
        0x0020:  a012 2000 6872 0000 0204 05b4 0103 0308  		....hr..........
        0x0030:  0402 080a 0045 65b5 0057 d308            		.....Ee..W..
3.	22:08:49.547773 IP 192.168.2.1.40776 > 192.168.4.2.6789: Flags [.], ack 1, win 229, options [nop,nop,TS val 5755657 ecr 4548021], length 0
        0x0000:  4500 0034 2dca 4000 4006 1b44 c0a8 3864  		E..4-.@.@..D..8d
        0x0010:  c0a8 3801 8f9b 1a85 3119 fec2 7006 4a6a  		..8.....1...p.Jj
        0x0020:  8010 00e5 b659 0000 0101 080a 0057 d309 		 .....Y.......W..
        0x0030:  0045 65b5                                			.Ee.
4.	22:08:57.043087 IP 192.168.2.1.40776 > 192.168.4.2.6789: Flags [P.], seq 1:2, ack 1, win 229, options [nop,nop,TS val 5763152 ecr 4548021], length 1
        0x0000:  4500 0035 2dcb 4000 4006 1b42 c0a8 3864  		E..5-.@.@..B..8d
        0x0010:  c0a8 3801 8f9b 1a85 3119 fec2 7006 4a6a  		..8.....1...p.Jj
        0x0020:  8018 00e5 f1dd 0000 0101 080a 0057 f050  		.............W.P
        0x0030:  0045 65b5 74                            			.Ee.t
5.	22:08:57.249548 IP 192.168.4.2.6789 > 192.168.2.1.40776: Flags [.], ack 2, win 260, options [nop,nop,TS val 4548791 ecr 5763152], length 0
        0x0000:  4500 0034 6022 4000 8006 a8eb c0a8 3801  		E..4`"@.......8.
        0x0010:  c0a8 3864 1a85 8f9b 7006 4a6a 3119 fec3  		..8d....p.Jj1...
        0x0020:  8010 0104 95f0 0000 0101 080a 0045 68b7 		 .............Eh.
        0x0030:  0057 f050                                			.W.P
6.	22:08:57.249855 IP 192.168.2.1.40776 > 192.168.4.2.6789: Flags [P.], seq 2:21, ack 1, win 229, options [nop,nop,TS val 5763359 ecr 4548791], length 19
        0x0000:  4500 0047 2dcc 4000 4006 1b2f c0a8 3864  		E..G-.@.@../..8d
        0x0010:  c0a8 3801 8f9b 1a85 3119 fec3 7006 4a6a  		..8.....1...p.Jj
        0x0020:  8018 00e5 f1ef 0000 0101 080a 0057 f11f  		.............W..
        0x0030:  0045 68b7 6573 7420 6672 6f6d 2072 6f75  		.Eh.est.from.rou
        0x0040:  7465 7220 7231 0a                        			ter.r1.
7.	22:08:57.253348 IP 192.168.4.2.6789 > 192.168.2.1.40776: Flags [P.], seq 1:2, ack 21, win 260, options [nop,nop,TS val 4548792 ecr 5763359], length 1
        0x0000:  4500 0035 6023 4000 8006 a8e9 c0a8 3801  		E..5`#@.......8.
        0x0010:  c0a8 3864 1a85 8f9b 7006 4a6a 3119 fed6  		..8d....p.Jj1...
        0x0020:  8018 0104 4104 0000 0101 080a 0045 		68b8  ....A........Eh.
        0x0030:  0057 f11f 54                            			.W..T
8.	22:08:57.253745 IP 192.168.2.1.40776 > 192.168.4.2.6789: Flags [.], ack 2, win 229, options [nop,nop,TS val 5763362 ecr 4548792], length 0
        0x0000:  4500 0034 2dcd 4000 4006 1b41 c0a8 3864  		E..4-.@.@..A..8d
        0x0010:  c0a8 3801 8f9b 1a85 3119 fed6 7006 4a6b  		..8.....1...p.Jk
        0x0020:  8010 00e5 9528 0000 0101 080a 0057 f122  		.....(.......W."
        0x0030:  0045 68b8                                			.Eh.
9.	22:08:57.253871 IP 192.168.4.2.6789 > 192.168.2.1.40776: Flags [P.], seq 2:21, ack 21, win 260, options [nop,nop,TS val 4548792 ecr 5763362], length 19
        0x0000:  4500 0047 6024 4000 8006 a8d6 c0a8 3801  		E..G`$@.......8.
        0x0010:  c0a8 3864 1a85 8f9b 7006 4a6b 3119 fed6  		..8d....p.Jk1...
        0x0020:  8018 0104 f39c 0000 0101 080a 0045 68b8  		.............Eh.
        0x0030:  0057 f122 4553 5420 4652 4f4d 2052 4f55  		.W."EST.FROM.ROU
        0x0040:  5445 5220 5231 0a                        			TER.R1.
10.	22:08:57.253981 IP 192.168.2.1.40776 > 192.168.4.2.6789: Flags [.], ack 21, win 229, options [nop,nop,TS val 5763363 ecr 4548792], length 0
        0x0000:  4500 0034 2dce 4000 4006 1b40 c0a8 3864  		E..4-.@.@..@..8d
        0x0010:  c0a8 3801 8f9b 1a85 3119 fed6 7006 4a7e  		..8.....1...p.J~
        0x0020:  8010 00e5 9514 0000 0101 080a 0057 f123 		 .............W.#
        0x0030:  0045 68b8                                			.Eh.
11.	22:08:57.257693 IP 192.168.2.1.40776 > 192.168.4.2.6789: Flags [F.], seq 21, ack 21, win 229, options [nop,nop,TS val 5763366 ecr 4548792], length 0
        0x0000:  4500 0034 2dcf 4000 4006 1b3f c0a8 3864  		E..4-.@.@..?..8d
        0x0010:  c0a8 3801 8f9b 1a85 3119 fed6 7006 4a7e  		..8.....1...p.J~
        0x0020:  8011 00e5 9510 0000 0101 080a 0057 f126 		 .............W.&
        0x0030:  0045 68b8                               			.Eh.
12.	22:08:57.257872 IP 192.168.4.2.6789 > 192.168.2.1.40776: Flags [.], ack 22, win 260, options [nop,nop,TS val 4548792 ecr 5763366], length 0
        0x0000:  4500 0034 6026 4000 8006 a8e7 c0a8 3801  		E..4`&@.......8.
        0x0010:  c0a8 3864 1a85 8f9b 7006 4a7e 3119 fed7  		..8d....p.J~1...
        0x0020:  8010 0104 94f1 0000 0101 080a 0045 68b8  		.............Eh.
        0x0030:  0057 f126                                			.W.&
			 
			 

Phân tích dữ liệu log từ chương trình tcpdump cho thấy:

  • Quá trình bắt tay 3 bước được thực hiện giữa client và server tại dòng log số 1,2,3.
  • Khi client yêu cầu gửi lên server xâu “test from router r1”, cài đặt thư viên Java socket xử lý bằng cách tách thành 2 gói tin TCP. Gói tin thứ nhất chứa byte đầu tiên của xâu (là ký tự “t”) và được gửi lên server (dòng log số 4). Server gửi ACK xác nhận đã nhận tốt gói tin này (dòng log số 5). Gói tin thứ 2 chứa phần còn lại của xâu (là “est from router r1”) và được gửi lên server (dòng log số 6). Server gửi ACK xác nhận đã nhận tốt gói tin này (dòng log số 7).
  • Phía server gửi về client xâu “TEST FROM ROUTER R1” cũng được thực hiện bằng 2 gói tin TCP. Gói đầu chứa ký tự “T” và gói sau chứa phần còn lại của xâu (“EST FROM ROUTER R1”). Điểm cần lưu ý ở đây là server sử dụng chung một gói tin (dòng log số 7) để truyền đi ký tự “T” và đồng thời xác nhận ACK cho gói tin vừa nhận từ client (là gói tin ở dòng log thứ 6). Client gửi xác nhận ACK về server của thông báo đã nhận tốt gói tin này (được hiển thị ở dòng log số 8). Tiếp theo, gói tin “EST FROM ROUTER R1” được server gửi về client (dòng log số 9) và client gửi ACK xác nhận đã nhận tốt (dòng log số 10).
  • Dòng log số 11&12 hiển thị các bước kết thúc kết nối do phía client yêu cầu.