[ENC28J60] Bài 16: Giao thức TCP Client – Kết nối tới 1 server trong LAN

giao thuc tcp

Chúng ta đã làm quen với giao thức TCP Client chế độ Server, với TCP Client, mọi thứ khó hơn rất nhiều, cũng giống như các bài trước, mình sẽ làm với từng phần nhỏ một. Ở bài này chúng ta sẽ thử cho ENC28J60 kết nối với một TCP trong mạng LAN nhé !

Chú ý: Mình đã chuyển project sang chíp stm32f103c8t6, các bạn phải đọc bài 15 trước nhé

http://iot47.com/enc28j60-bai-15-giao-thuc-dhcp-lay-ip-dong/

Các bước thiết lập kết nối

  • Client gửi bản tin SYN với 1 Sequence_Number bất kì
  • Server sẽ trả về bản tin SYN|ACK với Acknowledgement = Sequence_Number +1
  • Client trả lại với bản tin ACK

Hoàn tất kết nối. Sau khi kết nối thành công, chúng ta sẽ không cho Client kết nối lại nữa nhé vì điều này là không cần thiết

Ở trong file tcp.h chúng ta đĩnh nghĩa thêm 1 struct để lưu các thông tin kết nối với Server

Khởi tạo Struct TCP_client vào đầu file tcp.c nhé

Biến tcp_status

tcp_status = 1 => đã gửi gói tin SYN, đang chờ SYN|ACK
tcp_status = 2 =>đã nhận được SYN|ACK, đã phản hồi ACK, kết nối thành công

Trong hàm TCP_make_herder chúng ta thêm đoạn code make gói tin connect, gói tin connect sẽ mặc định là có 66 byte data

Và định nghĩa FOR_CONNECT có giá trị là 5 vào file tcp.h

Viết hàm gửi gói tin SYN

Để gửi gói tin connect vào 1 thiết bị trong mạng LAN, cần phải có địa chỉ MAC, mình sử dụng hàm ARP_table_get_MAC để lấy

Hàm này trả về 0 nếu không thể lấy MAC thành công, và trả về 1 nếu lấy thành công, đồng thời nó cũng lưu địa chỉ MAC đã lấy được vào struct tcp_client1 luôn

Sau khi gửi xong bản tin SYN, mình sẽ phải chờ bản tin SYN|ACK của server trả về, do phải chờ nên ta sẽ cần 1 cái timeout, nếu quá hạn thì thử gửi lại xem sao.

Hàm TCP_Connect sẽ làm nhiệm vụ trên

Ở đây, mình thêm vào tham số Try_reconnect, tức là số lần cố gắng thử kết nối lại nếu kết nối thất bại. Hàm này sẽ trả về 0 nếu kết nối hoàn toàn thất bại, 1 nếu kết nối thành công, 2 nếu đã kết nối rồi. Không kết nối nữa !

Nhận bản tin SYN|ACK

Trong hàm tcp_read, chúng ta thêm code kiểm tra cờ SYN|ACK

OK. Bây giờ test thử thôi

Khởi tạo server TCP trên máy tính bằng phần mềm Hercules -> TCP Server. Chọn Port 80 -> Listen

Trong file code chính (main.c) mình sẽ add địa chỉ server của máy tính mình đang dùng, nếu các bạn không biết IP của máy tính thì vào cmdipconfig hoặc tra google với từ khóa “cách kiểm tra ip máy tính” hoặc tham khảo hướng dẫn ở đây

Ví dụ, laptop của mình có ip 192.168.1.18

Quay trở lại hàm main và gọi TCP_Connect(ip_server,80,5000,5);

Ở đây, tham số 80 chính là port của server mà mình đã lắng nghe ở phần mềm Hercules, 5000 là timeout của mỗi lần connect và 5 là số lần cố gắng thử kết nối lại nếu thất bại

Chạy chương trình và xem màn hình debug

Như vậy mình đã kết nối thành công tới máy chủ do laptop của mình tạo ra. Và trong tab TCP_Server của phần mềm Hercules cũng sẽ có 1 thông báo có 1 client connect tới

Ngắt kết nối

Server có thể chủ động ngắt kết nối bằng bản tin FIN, do vậy chúng ta bắt sự kiện này ở bản tin FIN|ACK đồng thời kiểm tra Acknowledgement xem có trùng với Sequence_Number đã lưu ở trong Struct tcp_client1 không ! Nếu đúng thì mình sẽ reset lại tcp_status

Trong hàm TCP_read tại chỗ kiểm tra cờ TCP_FIN|TCP_ACK, thêm

Sau khi kết nối thành công, hãy ấn nút Close trên tab TCP_Server trên tab Hercules, điều này sẽ khiến phần mềm tự động ngắt kết nối với tất cả client

Và đây là toàn bộ quá trình kết nối và ngăt được WireShark ghi lại

Client chủ động ngắt kết nối

Client sẽ chủ động gửi FIN|ACK để ngắt kết nối tới Server

Thêm phần make hearder cho gói disconect trong hàm TCP_make_herder

Và tạo thêm hàm TCP_Disconect

Ở hàm main, sau khi kết nối thành công mình sẽ thử ngắt kết nối luôn để test hàm ngắt kết nối

Tải FULL Source tại đây
https://drive.google.com/open?id=1LNJPPLRa7aYyXL2uvuLArdp7aOn3KCLA

Lưu ý: Thư viện enc28j60 nằm ở : \code\Drivers\IOT47_lib\ENC28J60

Theo dõi toàn bộ tutorial enc28j60 tại đây

 

Từ tác giả:

Nếu có bất kì thắc mắc nào trong bài viết, vui lòng để lại comment dưới mỗi bài ! Mình sẽ không trả lời thắc mắc của các bạn ở facebook hay email !

Nếu trong phần code bạn nhìn thấy nhưng thứ kiểu như &amp; thì đó là lỗi hiển thị, cụ thể 3 kí tự < > & bị biến đổi thành như thế
&amp; là &
&lt;  là <
&gt; là >

Giới thiệu Đào Nguyện 80 bài viết
DIY,chế cháo, viết blog chia sẽ kiến thức về lập trình,điện tử - IoT. Rất mong được giao lưu, kết bạn với các bạn cùng đam mê. Địa chỉ Facebook: https://www.facebook.com/nguyendao207

3 bình luận

  1. Chào Đào Nguyện
    Trước hết cảm ơn bạn vì Series chia sẻ hữu ích
    Mình có tải Source bài 16, thay đổi IP bằng IP của máy mình. Bật listen TCP Server trên Hercules. Rồi dùng hàm TCP_Connect() nhưng không kết nối được.
    Mình có kiểm tra bằng Wireshark thì IP và MAC của máy tính và ENC đều đúng hết. nhưng k thấy máy tính gửi gói (SYN | ACK).
    Nhờ bạn cho mình lời khuyên với. Cảm ơn bạn

  2. cảm ơn ban đã chia sẻ. mình có 1 vấn đề lỗi thế này: khi mình cho ENC làm client thì nó trao đổi dữ liệu với Server OK. nhưng sau đó mình test với chế độ ngược lại đó là ENC là Server, hercules làm client thì khi connect thì trên hercules báo connected và nên ENC đã lấy dc địa chỉ MAC nhưng không thể trao đổi dữ liệu cho nhau. client dửi dữ liệu cho ENC thì ko thấy ENC in data ra. và cờ PSH|ACK từ clinet được retransmit liên tục đến 5 lần. ENC cũng ko thể gửi dữ liệu lại cho client và nó báo ko có kết nối. bạn cho mình cách FIX nhé, cảm ơn bạn rất nhiều

Đã đóng bình luận.