Thông báo

Collapse
No announcement yet.

Giao thức TCP/IP và Web server với AVR

Collapse
This is a sticky topic.
X
X
 
  • Lọc
  • Giờ
  • Show
Clear All
new posts

  • #76
    Hàm TCPProcess:
    Hàm này dài quá nên chỉ giải thích cấu trúc hàm cho các bạn dễ đọc thôi:
    Khai báo các biến sử dụng:
    Code:
    	unsigned char i,ipHeaderLen,tcpHeaderLen;
    	unsigned int dataLen;
    	unsigned long tmp;
    	struct ntIPHeader* ipHeader;
    	struct ntTCPHeader* tcpHeader;
    	unsigned char *tcpData;
    Trỏ các biến con trỏ header IP và TCP đến vùng header tương ứng. Lúc này trên buffer đã có đầy đủ frame dữ liệu đọc từ ENC28J60.
    Code:
    	//Khoi tao cac co tro den Header IP va TCP
    	ipHeader = (struct ntIPHeader*)(buffer);
    	ipHeaderLen = ((ipHeader->verHdrLen) & 0x0F) << 2;
    	//
    	tcpHeader = (struct ntTCPHeader*)(buffer+ipHeaderLen);
    	tcpHeaderLen = ((tcpHeader->Offset) & 0xF0) >> 2;
    	//
    	tcpData = (buffer+ipHeaderLen+tcpHeaderLen);
    	dataLen = HTONS(ipHeader->Len) - (ipHeaderLen + tcpHeaderLen);
    Sau khi đọc được địa chỉ IP nguồn của host gửi và port nguồn, port đích, ta tìm kiếm trong TCP session table phiên TCP có sẵn tương ứng với gói tin này, nếu chưa tồn tại thì khởi tạo session mới:
    Code:
    	if(i == TCP_MAX_SESSION){	//Neu khong co 1 phien TCP dang ton tai cho goi nay
    		//Tim 1 phien dang o trang thai LISTEN (doi ket noi) cho local port nay
    		for(i=0; i < TCP_MAX_SESSION; i++){
    			if(tcpSessionTable[i].sesState == TCP_STATE_LISTEN){
    				if(tcpSessionTable[i].srcPort == HTONS((tcpHeader->desPort))){	//If matched local port
    					//Cap nhat remote port va remote IP
    					tcpSessionTable[i].desPort = HTONS((tcpHeader->srcPort));
    					tcpSessionTable[i].desIP = HTONL((ipHeader->srcIPAddr));
    					//Dong thoi tao ra 1 session moi de cho ket noi khac den local port nay
    					TCPCreateSession(tcpSessionTable[i].srcPort,tcpSessionTable[i].appDataIn);
    					break;
    				}
    			}
    		}
    	}
    	if(i == TCP_MAX_SESSION){
    		#ifdef TCP_DEBUG
    		printf("No TCP session found\r\n");
    		#endif
    		return;	//Neu khong co phien TCP nao danh cho goi nay thi thoat ra
    	}
    	#ifdef TCP_DEBUG
    	printf("TCP session found: %d\r\n",i);
    	#endif
    Ta reset biến Timeout mỗi khi nhận được gói tin. Biến này nhằm phát hiện và hủy bỏ các phiên TCP bị “treo” một thời gian dài mà không nhận được dữ liệu.
    Code:
    	tcpSessionTable[i].timeOut = TCP_TIMEOUT;	//Reset lai gia tri Time out
    Nếu cờ RST=1 (Reset). Đóng kết nối.
    Code:
    	if ((tcpHeader->Flags) & TCP_RST_FLAG){
    		//Chap nhan dong ket noi
    		TCPCloseSession(i);
    		return;
    	}
    Tiếp theo, ta phải xử lý theo lưu đồ trạng thái của TCP. Ta dùng 1 cấu trúc switch…case để xử lý tùy vào trạng thái hiện tại của kết nối:
    Code:
    	switch (tcpSessionTable[i].sesState){
    		//Neu la trang thai doi ket noi: TCP_STATE_LISTEN
    		case(TCP_STATE_LISTEN):
    			break;
    		//Neu la trang thai TCP_STATE_SYN_RECEIVED
    		case(TCP_STATE_SYN_RECEIVED):
    			break;
    		//Truong hop ket noi da duoc thiet lap
    		case(TCP_STATE_ESTABLISHED):
    			break;
    		//Neu la trang thai doi LAST_ACK (2 phia deu san sang dong ket noi, dang doi xac nhan ack cuoi cung)
    		case(TCP_STATE_LAST_ACK):
    			break;
    		//Truong hop ngat ket noi thu dong, da nhan co FIN tu remote host va xac nhan
    		case(TCP_STATE_CLOSE_WAIT):
    			break;
    		//Truong hop dang o trang thai FIN WAIT 1 (da truyen du lieu xong,
    		//  san sang dong ket noi va da gui di co FIN va dang cho ACK)
    		case(TCP_STATE_FIN_WAIT1):
    			break;
    		//Neu dang o trang thai FIN WAIT 2 (san sang dong ket noi va gui co FIN,
    		//  phia ben kia da xac nhan nhung van chua san sang dong ket noi
    		case(TCP_STATE_FIN_WAIT2):
    			break;
    		case(TCP_STATE_TIMED_WAIT):
    			break;
    		case(TCP_STATE_CLOSING):
    			break;
    		default:
    			TCPCloseSession(i);
    	}
    Trong mỗi trạng thái, ta xử lý thông tin trong header TCP và chuyển trạng thái tương ứng. Mọi người tự đọc nhé .

    Comment


    • #77
      Bài 6: Các giao thức lớp ứng dụng

      Giao thức DHCP:
      - DHCP là một giao thức được sử dụng để phân phối động các tham số cấu hình TCP/IP cho các máy tính. Một DHCP server có thể cho client DHCP một số thiết lập TCP/IP, như là địa chỉ IP, subnet mask, và máy chủ DNS.
      - Mỗi client sẽ nhận một hợp đồng thuê địa chỉ trong thời gian hạn định. Nếu client không còn sử dụng địa chỉ khi hợp đồng thuê hết hạn, địa chỉ đó có thể cấp phát cho các client khác.
      Cơ chế làm việc của DHCP: gồm có 4 bản tin chính:
      + DHCPDISCOVER: DHCP client khởi tạo tiến trình bằng cách quảng bá một gói tới cổng UDP 68 (sử dụng cho máy chủ BOOTP và DHCP). Gói đầu tiên này được gọi là bản tin DHCP Discover, nó sẽ yêu cầu bất cứ DHCP server nào nhận được gói thực hiện việc cấu hình. Gói DHCP discover gồm rất nhiều trường, nhưng một vùng quan trọng nhất chứa địa chỉ vật lý của DHCP client.


      + DHCPOFFER: Một DHCP server được cấu hình cung cấp hợp đồng địa chỉ cho mạng mà client cư trú sẽ đáp ứng lại một gói tên là DHCP offer và gửi nó dưới dạng quảng bá tới máy đưa ra DHCP discover. Thông điệp quảng bá này được gửi tới cổng UDP 67 và bao gồm địa chỉ vật lý của client, địa chỉ vật lý và địa chỉ IP của DHCP server, cũng như giá trị địa chỉ IP và subnet mask cung cấp cho DHCP client.


      + DHCPREQUEST: Client chọn một DHCP offer, tạo một gói DHCP request và quảng bá gói này. Gói DHCP request này bao gồm địa chỉ IP của server phát ra DHCP offer và địa chỉ vật lý của DHCP client. DHCP request này thực hiện hai việc:
      . Báo cho DHCP server được chọn rằng nó yêu cầu một địa chỉ IP.
      . Thông báo cho các DHCP server khác là DHCP offer của chúng không được chấp nhận.


      + DHCPACK: Khi DHCP server được chọn nhận được DHCP request, nó sẽ trả lời bắng gói DHCP ack. DHCP ack bao gồm địa chỉ IP và subnetmask cho DHCP client. Ngoài các thông tin về địa chỉ IP, DHCP client có thể nhận thêm các thông tin cấu hình như địa chỉ IP của gateway, máy chủ DNS, ...
      Last edited by nttam79; 11-11-2011, 11:48.

      Comment


      • #78
        Theo em biết PIC18F67J60 cũng có chức năng giao tiếp ethernet và kinh tế hơn ENC28J60. Nếu dùng PIC thì mình không những giao tiếp được ethernet mà còn lập trình điều khiển các IO ngoại vi khác. Nếu dùng ENC28J60 thì phải có thêm 1 ATmega32 đi kèm nên lại tốn. Em chỉ biết vậy và đang phân vân không biết dùng linh kiện nào. Thầy tâm cho em 1 lời khuyên đi ạ !

        Comment


        • #79
          Xin lỗi mọi người nhé. Cuối tuần rồi bận tham gia study trip với SV, về mệt quá nên không update gì cho thread, tối nay sẽ đền bù.
          @GaCon_: giải pháp dùng với ATmega32 là cho những bạn dùng AVR, còn nếu dùng pic thì có rất nhiều cách, PIC18F67J60 hoặc 1 pic18 khác cộng ENC26J60 (nhiều khi rẻ hơn PIC18F67J60.
          Trước đây tôi có hướng dẫn 1 bạn SV làm đề tài tương tự, dùng PIC18F97J60, tính ra không rẻ hơn pic18+enc, tuy nhiên PIC18F67J60 thì có thể rẻ hơn, tùy bạn thôi.

          Comment


          • #80
            Nguyên văn bởi nttam79 Xem bài viết
            Xin lỗi mọi người nhé. Cuối tuần rồi bận tham gia study trip với SV, về mệt quá nên không update gì cho thread, tối nay sẽ đền bù.
            @GaCon_: giải pháp dùng với ATmega32 là cho những bạn dùng AVR, còn nếu dùng pic thì có rất nhiều cách, PIC18F67J60 hoặc 1 pic18 khác cộng ENC26J60 (nhiều khi rẻ hơn PIC18F67J60.
            Trước đây tôi có hướng dẫn 1 bạn SV làm đề tài tương tự, dùng PIC18F97J60, tính ra không rẻ hơn pic18+enc, tuy nhiên PIC18F67J60 thì có thể rẻ hơn, tùy bạn thôi.
            Nếu tính giá PIC+enc thì có thể không rẻ hơn, nhưng tính chung lại toàn bộ sản phẩm chắc chắn sẽ rẻ hơn khi dùng PIC ethernet, vì sẽ giảm bớt công thiết kế mạch, giảm bớt giá thành mạch in, linh kiện phụ...

            Comment


            • #81
              Nguyên văn bởi nttam79 Xem bài viết
              Xin lỗi mọi người nhé. Cuối tuần rồi bận tham gia study trip với SV, về mệt quá nên không update gì cho thread, tối nay sẽ đền bù.
              @GaCon_: giải pháp dùng với ATmega32 là cho những bạn dùng AVR, còn nếu dùng pic thì có rất nhiều cách, PIC18F67J60 hoặc 1 pic18 khác cộng ENC26J60 (nhiều khi rẻ hơn PIC18F67J60.
              Trước đây tôi có hướng dẫn 1 bạn SV làm đề tài tương tự, dùng PIC18F97J60, tính ra không rẻ hơn pic18+enc, tuy nhiên PIC18F67J60 thì có thể rẻ hơn, tùy bạn thôi.
              em cũng đang làm về pic18 +enc28j60
              em biên dịch chương trình demo của microchip thì ok.
              nhưng khi em tạo 1 project khác và copy toàn bộ code của microchip sang thì khi biên dịch nó lại mắc lỗi như này: Error [1027] unable to locate 'TCPIP Stack/TCPIP.h'
              tại sao cái file "TCPIP Stack/TCPIP.h" ko có trong khi mọi file *.h trong Microchip stack đều include nó hết.
              khi dịch bản demo thì lại được
              mà khi tự tạo 1 project mới thì khi dịch lại báo lỗi : Error [1027] unable to locate 'TCPIP Stack/TCPIP.h'
              cám ơn thầy!
              p/s:nếu có sai toppic thì mọi người thông cảm nhé vì nếu ai mà làm với pic + enc28j60 cũng sẽ mắc lỗi này

              Comment


              • #82
                Nguyên văn bởi kiemkhach10 Xem bài viết
                em cũng đang làm về pic18 +enc28j60
                em biên dịch chương trình demo của microchip thì ok.
                nhưng khi em tạo 1 project khác và copy toàn bộ code của microchip sang thì khi biên dịch nó lại mắc lỗi như này: Error [1027] unable to locate 'TCPIP Stack/TCPIP.h'
                tại sao cái file "TCPIP Stack/TCPIP.h" ko có trong khi mọi file *.h trong Microchip stack đều include nó hết.
                khi dịch bản demo thì lại được
                mà khi tự tạo 1 project mới thì khi dịch lại báo lỗi : Error [1027] unable to locate 'TCPIP Stack/TCPIP.h'
                cám ơn thầy!
                p/s:nếu có sai toppic thì mọi người thông cảm nhé vì nếu ai mà làm với pic + enc28j60 cũng sẽ mắc lỗi này
                File "TCPIP.h" nằm trong thư mục "Include/TCPIP Stack/" cùng với các file header khác mà. Có thể là em chép thiếu thư mục Include hoặc không chỉ định thư mục chứa Header (Include Diectory) cho Project mới thôi.

                Comment


                • #83
                  Nguyên văn bởi nttam79 Xem bài viết
                  Có lẽ mình cần dừng lại để giải thích rõ hơn về hoạt động của 2 giao thức IP và ARP một chút, cũng như các sử dụng 2 loại địa chỉ IP và MAC trên mạng, trước khi viết code tiếp, tuy hơi dài dòng 1 chút nhưng sẽ giúp mọi người hiểu rõ hơn cách thức làm việc của TCP/IP, như vậy thì sẽ dễ hiểu code hơn và có thể tự viết hay sửa đổi code được dễ dàng.

                  Ta hãy xem xét 1 mạng ví dụ như sau:
                  - Mạng LAN tại nhà gồm 3 máy tính và 1 board mạch của chúng ta kết nối vào ADSL router, từ đó nối vào mạng của nhà cung cấp dịch vụ.
                  - Các bạn cũng cần biết là thực ra modem ADSL hay ADSL router mà ta dùng ở nhà, thật ra bên trong nó gồm 3 thiết bị: một HUB để mở rộng số lượng port, cho phép nhiều máy tính có thể cùng kết nối vào mạng; một Router IP đóng vai trò Gateway, thực hiện chức năng định tuyến giữa mạng bên trong (LAN) và mạng bên ngoài (WAN); và cuối cùng là 1 modem (Modulation - Demodulation) để có thể truyền dữ liệu trên đường dây ADSL.

                  Ta xẽ xem xét 2 ví dụ:
                  Ví dụ A: board mạch của chúng ta gửi dữ liệu đến 1 máy tính trong cùng mạng LAN, ví dụ là máy có địa chỉ 192.168.1.6.
                  Ví dụ B: board mạch gửi dữ liệu đến 1 máy tính nằm bên ngoài, ví dụ là máy có địa chỉ 203.162.44.164
                  A-Trường hợp gửi trong mạng LAN
                  Bước 1: Giao thức IP trong board mạch nhận được yêu cầu gửi dữ liệu đến địa chỉ IP 192.168.1.6
                  Bước 2: Nó đi hỏi giao thức ARP (thông qua hàm ArpIpOut) về địa chỉ này. ARP sau khi tìm trong bảng ARP cache không thấy, nó sẽ gửi 1 bản tin ARP request dưới hình thức broadcast đến mọi máy tính trong mạng. Máy tính có địa chỉ tương ứng sẽ trả lời.


                  Bước 3: ARP sẽ cập nhật bảng ARP cache và trả lời lại cho giao thức IP.
                  Bước 4: giao thức IP dùng thông tin này để điền vào frame ethernet và chuyển sang giao thứ ethernet để gửi đi.


                  B-Trường hợp gửi ra ngoài mạng LAN
                  Nếu vẫn làm theo cách cũ thì sẽ xảy ra trường hợp như sau:




                  Như vậy, nếu vẫn làm theo cách cũ, việc gửi dữ liệu sẽ thất bại.
                  Mọi việc phải được tiến hành như sau:




                  Có ai biết cách post flash lên forum không? Xin chỉ giúp. Vài minh họa bằng ảnh động có lẽ dễ hiểu hơn.
                  Hi anh Tâm ! Vì em không phải là dân IT nên có nhiều thắc mắc lắm.
                  Cho em hỏi là trường hợp gởi ra ngoài mạng LAN. Ở phần 4a sau khi biết MAC của gateway rồi phần gói tin cần gởi đến 203.162.44.164 thì sẽ thực hiện như thế nào vậy.
                  Câu hỏi thứ 2: Có khi nào 2 địa chỉ MAC trùng nhau không và nếu trùng thì có phải lớp IP dùng để phân biệt các máy tính với nhau không.

                  Email:
                  Tel: 0983.497.310

                  Comment


                  • #84
                    Nguyên văn bởi tienhuypro Xem bài viết
                    Hi anh Tâm ! Vì em không phải là dân IT nên có nhiều thắc mắc lắm.
                    Cho em hỏi là trường hợp gởi ra ngoài mạng LAN. Ở phần 4a sau khi biết MAC của gateway rồi phần gói tin cần gởi đến 203.162.44.164 thì sẽ thực hiện như thế nào vậy.
                    Câu hỏi thứ 2: Có khi nào 2 địa chỉ MAC trùng nhau không và nếu trùng thì có phải lớp IP dùng để phân biệt các máy tính với nhau không.
                    Câu 1: Sau khi biết MAC của gateway, host gửi sẽ gửi gói IP đến Gateway thông qua địa chỉ MAC của nó (địa chỉ IP đích vẫn ghi là 203.162.44.164 nhưng địa chỉ MAC đích thì là của Gateway).

                    Khi nhận được gói tin, Gateway (chính là 1 router IP) sẽ kiểm tra địa chỉ mạng của địa chỉ IP đích (VD: trường hợp địa chỉ IP 203.162.44.164 thì địa chỉ mạng là 203.162.44.0 - 24 bit đầu). Sau đó nó đối chiếu địa chỉ mạng này với một bảng, gọi là bảng định tuyến (Routing table). Trong bảng định tuyến có lưu thông tin về các địa chỉ mạng và giao tiếp mạng tương ứng mà gói tin phải được chuyển tới, cũng như địa chỉ IP của Router tiếp theo sẽ chịu trách nhiệm chuyển gói tin đi. Gateway sẽ căn cứ vào các thông tin này để chuyển gói tin đi tiếp.

                    Ví dụ: ADSL router ở nhà mình có bảng định tuyến như sau (có thể truy cập vào trang cấu hình modem xem được bảng này):


                    Giải thích:
                    - Destination: địa chỉ đích, thường chỉ lưu địa phần chỉ mạng.
                    - Subnet Mask: mặt nạ mạng con tương ứng với địa chỉ đích đó.
                    - Next hop: router kế tiếp sẽ nhận nhiệm vụ chuyển gói tin.
                    - Metric: số chặng (số router) mà gói tin phải đi qua để đến được đích này (sử dụng cho các giao thức định tuyến).
                    - Interface: giao diện (hay kết nối mạng) mà router phải chuyển gói tin đó ra. Trong trường hợp ADSL router của mình, nó chỉ có 2 interface: kết nối vào mạng LAN bên trong (nó đặt tên là br0) và kết nối ra bên ngoài (nó đặt tên là ppp0).

                    1-Dòng đầu tiên cho biết: nếu địa chỉ đích là 123.20.128.1 (đây chính là địa chỉ của Router biên của ISP mà ADSL router của mình kết nối đến), thì nó cần chuyển dữ liệu ra giao tiếp (interface) ppp0 (đây chính là kết nối WAN của modem ADSL, xem thêm các minh họa sơ đồ mạng bên dưới). Next hop= * có nghĩa là nó không cần thông qua router nào khác nũa mà có kết nối trực tiếp đến destination.
                    2-Dòng thứ 2: nếu đích là 192.168.0 (đây là địa chỉ của mạng LAN), thì nó phải chuyển gói tin vào giao tiếp mạng LAN bên trong (interface = br0). Tương tự, không có Next hop.
                    3-Dòng thứ 3: nếu đích là 127.0.0.0 (đây là địa chỉ loopback, gửi cho chính mình) thì nó không chuyển ra giao tiếp nào hết mà là cho chính nó (Interface = lo).
                    4-Dòng thứ 4: Mọi trường hợp địa chỉ đích khác (Destination = 0.0.0.0; Subnet Mask = 0.0.0.0), nó sẽ chuyển ra giao tiếp mạng bên ngoài (Interface = ppp0), và gửi đến router kế tiếp sẽ chịu trách nhiệm chuyển gói tin đi là router biên của ISP (địa chỉ là 123.20.128.1)

                    Ví dụ minh họa:
                    Đây là sơ đồ mạng (địa chỉ IP của các Router lõi chỉ la minh họa, không chính xác vì mình không có các thông tin này)


                    Bước 1: sau khi Gateway (ADSL router) nhận được gói tin có địa chỉ đích là 203.162.44.164, nó sẽ tra bảng ĐT của nó và thấy tương ứng với dòng này (destination = 0.0.0.0), nó sẽ chuyển gói tin ra giao tiếp mạng WAN (ppp0) đến router kế tiếp là 123.20.128.1 (bằng cách ghi địa chì MAC của router kế tiếp vào phần destination MAC Address trong frame ethernet).


                    Bước 2: Router biên của ISP (123.20.128.1) nhận gói tin, tra trong bảng ĐT của nó, tìm dòng tương ứng, căn cứ vào đó nó chuyển gói tin ra interface số 1 của nó (kết nối tới router lõi) và gủi đến cho router lõi (123.20.64.1).


                    Bước 3: Router lõi này nhận gói tin, lại tra bảng ĐT của nó, sau đó chuyển gói tin ra interface 3 của nó đến router lõi thứ hai (123.20.66.1).


                    Bước 4: Tương tự, router lõi thứ hai nhận gói tin, tra bảng và chuyển đến router kế là router biên thứ hai (123.20.66.5) qua interface 3 của nó.


                    Bước 5: Cuối cùng, đến lượt router biên ở ngõ ra nhận gói tin, tra bảng ĐT, chuyển gói đến thẳng đích mà không cần qua router nào nữa.


                    Câu 2: Về lý thuyết, mỗi nhà sản xuất có sản xuất thiết bị mạng sẽ được cấp một khoảng địa chỉ MAC (các byte đầu trong địa chỉ MAC từ 1 nhà sản xuất sẽ giống nhau. Ví dụ: 3 byte đầu của 3com là: 00A024, của Apple là 00A040,...). Sau đó khi sản xuất ra mỗi thiết bị, nhà sản xuất sẽ đánh số địa chỉ MAC của chúng khác nhau. Như vậy, về lý thuyết, địa chỉ MAC không trùng nhah.
                    Tuy nhiên rất nhiều thiết bị (VD IC ENC28J60, nhiều loại card mạng máy tính) cho phép thay đổi địa chỉ MAC, do đó trong thực tế, việc trùng địa chỉ MAC hoàn toàn có thể xảy ra. Trong trường hợp đó: ví dụ trong mạng LAN có 2 máy trùng địa chỉ MAC, khi dữ liệu được gửi ở lớp truy nhập mạng (switch hay hub chuyển đi) thì đồng thời cả 2 máy đó đều nhận được nếu dữ liệu gửi cho 1 trong 2 máy. Tuy nhiên khi dữ liệu được chuyển lên lớp IP, địa chỉ IP sẽ được kiểm tra (có thể xem code của phần giao thức IP để thấy việc kiểm tra này), nếu không đúng địa chỉ IP, dữ liệu sẽ bị bỏ qua.
                    Nếu 2 máy tính trùng địa chỉ MAC nằm ở 2 mạng LAN khác nhau, việc này sẽ không ảnh hưởng gì, vì khi chuyển dữ liệu giữa các mạng LAN sẽ do router thực hiện, mà như đã nói ở trên, router sẽ căn cứ vào địa chỉ IP chứ không phải địa chỉ MAC.
                    Hy vọng câu trả lời của mình giải đáp được thắc mắc của Huy, nếu chưa rõ cứ hỏi tiếp nhé. Mình có các slide với animation minh hoạt các hoạt động này, nhưng không biết làm sao post lên, vì dd không hỗ trợ post flash thì phải.
                    Last edited by nttam79; 16-11-2011, 03:21. Lý do: Thêm minh họa

                    Comment


                    • #85
                      Thưa thầy ,em xin hỏi mấy câu :
                      MAC gateway là mình lấy từ modem ADSL?.Em gửi gói arp request đến địa chỉ ip 192.168.1.1 (gateway) để hỏi địa chỉ MAC của nó có được kô.Em thấy trong code của thầy thì gói arp,ethernet,ip chỉ có phần header.Vậy có phải chỉ có lớp ứng dụng mới chứa data?.Em mới viết code đến đây thôi.Em cảm ơn thầy nhiều.
                      , , ,

                      Comment


                      • #86
                        Nguyên văn bởi rptdnmqs Xem bài viết
                        Thưa thầy ,em xin hỏi mấy câu :
                        MAC gateway là mình lấy từ modem ADSL?.Em gửi gói arp request đến địa chỉ ip 192.168.1.1 (gateway) để hỏi địa chỉ MAC của nó có được kô.Em thấy trong code của thầy thì gói arp,ethernet,ip chỉ có phần header.Vậy có phải chỉ có lớp ứng dụng mới chứa data?.Em mới viết code đến đây thôi.Em cảm ơn thầy nhiều.
                        Trong mạng LAN dùng Modem ADSL thì gateway chính là modem ADSL, do vậy khi cần biết địa chỉ MAC của nó thì đương nhiên phải hỏi nó rồi, nhưng ở đây ta chưa biết địa chỉ MAC của nó nên ta phải gửi Broadcast (địa chỉ IP đích = 192.168.1.1, MAC đích = FF:FF:FF:FF:FF:FF).

                        Gateway chính là Router kết nối giữa mạng LAN với bên ngoài. Trong trường hợp này chính là ADSL Router.

                        Trong phần giao thức ARP đã post, thực ra tôi đã lách luật khi không gửi ARP request khi chưa biết địa chỉ MAC mà điền luôn địa chỉ MAC broadcast vào gói tin cần gửi đi (tôi có đố các bạn phát hiện ra chỗ lách luật này mà không thấy ai phản hồi). rptdnmqs có biết tại sao phải lách luật như vậy không?

                        - Data của ứng dụng chứa trong phần data của gói TCP hay UDP nằm ngay sau Header TCP/UDP.
                        - Gói IP thì nó xem toàn bộ gói TCP/UDP là data của nó, và Header của gói là Header IP.
                        - Tương tự, frame Ethernet coi toàn bộ gói IP là data của nó, Header là Header của frame ethernet.
                        - Vậy gói của giao thức nào cũng có data hết, có điều data của nó chính là toàn bộ gói của giao thức lớp trên.
                        - Còn dữ liệu ứng dụng trong gói TCP/UDP đương nhiên là chỉ do lớp ứng dụng tạo ra mà thôi.
                        Last edited by nttam79; 16-11-2011, 09:30. Lý do: Hiểu sai câu hỏi của rptdnmqs

                        Comment


                        • #87
                          Thầy cho em hỏi thêm câu nữa là cái trang web có chứa ảnh thì làm sao lưu lên rom được.Hay em upload ảnh lên 1 trang web khác rồi nhúng liên kết vào trang html.Em cảm ơn nhiều
                          , , ,

                          Comment


                          • #88
                            À, có thể lưu ảnh lên ROM được bằng cách chuyển dữ liệu ảnh sang nhị phân và lưu trong ROM bằng 1 array các char (viết dạng mã hex).

                            Tuy nhiên phải nói cách làm này phí phạm bộ nhớ ghê gớm, vì một ảnh thường thôi cũng vài kB đến vài chục kB rồi, mà con AVR của chúng ta có 32kB ROM thôi, viết chương trình đã gần hết. Nên cách tốt nhất vẫn là up ảnh lên chỗ khác rồi nhúng mã vào.

                            Comment


                            • #89
                              Nguyên văn bởi nttam79 Xem bài viết
                              File "TCPIP.h" nằm trong thư mục "Include/TCPIP Stack/" cùng với các file header khác mà. Có thể là em chép thiếu thư mục Include hoặc không chỉ định thư mục chứa Header (Include Diectory) cho Project mới thôi.
                              em chép đủ mà:
                              đây là project em gửi lên thầy và các bạn dịch thử xem sao.
                              cám ơn mọi người!
                              linhk download mong mọi người

                              http://www.mediafire.com/?5yy6ggp4vpv8zky
                              Last edited by kiemkhach10; 16-11-2011, 10:24.

                              Comment


                              • #90
                                Lỡ hẹn đã lâu, hôm nay tiếp tục với giao thức DHCP, còn thằng này với HTTP nữa là xong.

                                Trước hết, ta lại tạo 2 file source và header:
                                "dhcp.c"
                                Code:
                                //----------------------------------------------------------------------------
                                // Writen by NTTam - PTITHCM
                                //----------------------------------------------------------------------------
                                #include "packet.h"
                                #include "ethernet.h"
                                #include "ip.h"
                                #include "udp.h"
                                #include "dhcp.h"
                                #include "uart.h"
                                #include "ntAVRnet.h"
                                //
                                "dhcp.h"
                                Code:
                                //----------------------------------------------------------------------------
                                // Writen by NTTam - PTITHCM
                                //----------------------------------------------------------------------------
                                #ifndef DHCP_H
                                #define DHCP_H
                                
                                #include "packet.h"
                                //#define DHCP_DEBUG
                                Trong file Header, ta khai báo các Header BOOTP và DHCP:
                                Code:
                                //----------------------------------------------------------------------------
                                /// BOOTP Header
                                struct ntBootpHeader
                                {
                                	unsigned char	opcode;			//Message op-code / message type
                                	unsigned char	hwaddrtype;		//Hardware address type   (Ethernet=1)
                                	unsigned char	hwaddrlen;		//Hardware address length (Ethernet=6 byte MAC addr)
                                	unsigned char	hops;			//hop count (client set to zero)
                                	unsigned long	transid;		//Transaction ID (randomly chosen by client, must remain same)
                                	unsigned int	secs;			//Seconds elapsed since DHCP negotiation began (filled by client)
                                	unsigned int	flags;			//Flags
                                	unsigned long	clipaddr;		//Client IP address (filled only if already bound, renewing, or rebinding)
                                	unsigned long	yoipaddr;		//Your IP address (client)
                                	unsigned long	seipaddr;		//Server IP address
                                	unsigned long	gwipaddr;		//Gateway IP address
                                	unsigned char	clhwaddr[16];	//Client Hardware Address
                                	unsigned char	sename[64];		//Server Host Name
                                	unsigned char	file[128];		//Boot file name (null-term string)
                                };
                                //
                                #define BOOTP_HEADER_LEN		236	//length of BOOTP header not including options
                                //
                                #define BOOTP_OP_BOOTREQUEST	1	//BOOTP Request operation (message from client to server)
                                #define BOOTP_OP_BOOTREPLY		2	//BOOTP Reply operation (message from server to client)
                                //
                                #define BOOTP_HTYPE_ETHERNET	1	//Hardware type for ethernet protocol
                                #define BOOTP_HLEN_ETHERNET		6	//Length of ethernet MAC address
                                //----------------------------------------------------------------------------
                                struct netDhcpHeader
                                {
                                	struct ntBootpHeader bootp;		//BOOTP header
                                	unsigned long	cookie;			//magic cookie value
                                	unsigned char	options[1];		//DHCP options
                                };
                                //
                                #define DHCP_HEADER_LEN			240	//length of DHCP header not including options
                                Tiếp theo ta định nghĩa 1 số giá trị hằng được qui định cho các trường trong header:
                                Code:
                                //Code for DHCP option field
                                #define DHCP_OPT_PAD			0	//token padding value (make be skipped)
                                #define DHCP_OPT_NETMASK		1	//subnet mask client should use (4 byte mask)
                                #define DHCP_OPT_ROUTERS		3	//routers client should use (IP addr list)
                                #define DHCP_OPT_TIMESERVERS	4	//time servers client should use (IP addr list)
                                #define DHCP_OPT_NAMESERVERS	5	//name servers client should use (IP addr list)
                                #define DHCP_OPT_DNSSERVERS		6	//DNS servers client should use (IP addr list)
                                #define DHCP_OPT_HOSTNAME		12	//host name client should use (string)
                                #define DHCP_OPT_DOMAINNAME		15	//domain name client should use (string)
                                #define DHCP_OPT_REQUESTEDIP	50	//IP address requested by client (IP address)
                                #define DHCP_OPT_LEASETIME		51	//DHCP Lease Time (uint32 seconds)
                                #define DHCP_OPT_DHCPMSGTYPE	53	//DHCP message type (1 byte)
                                #define DHCP_OPT_SERVERID		54	//Server Identifier (IP address)
                                #define DHCP_OPT_PARAMREQLIST	55	//Paramerter Request List (n OPT codes)
                                #define DHCP_OPT_RENEWALTIME	58	//DHCP Lease Renewal Time (uint32 seconds)
                                #define DHCP_OPT_REBINDTIME		59	//DHCP Lease Rebinding Time (uint32 seconds)
                                #define DHCP_OPT_CLIENTID		61	//DHCP Client Identifier
                                #define DHCP_OPT_END			255 //token end value (marks end of options list)
                                //Code for DHCP message type
                                #define DHCP_MSG_DHCPDISCOVER	1	//DISCOVER is broadcast by client to solicit OFFER from any/all DHCP servers.
                                #define DHCP_MSG_DHCPOFFER		2	//OFFER(s) are made to client by server to offer IP address and config info.
                                #define DHCP_MSG_DHCPREQUEST	3	//REQUEST is made my client in response to best/favorite OFFER message.
                                #define DHCP_MSG_DHCPDECLINE	4	//DECLINE may be sent by client to server to indicate IP already in use.
                                #define DHCP_MSG_DHCPACK		5	//ACK is sent to client by server in confirmation of REQUEST, contains config and IP.
                                #define DHCP_MSG_DHCPNAK		6	//NAK is sent to client by server to indicate problem with REQUEST.
                                #define DHCP_MSG_DHCPRELEASE	7	//RELEASE is sent by client to server to relinquish DHCP lease on IP address, etc.
                                #define DHCP_MSG_DHCPINFORM		8	//INFORM is sent by client to server to request config info, IP address configured locally.
                                Định nghĩa port UDP được qui định dành cho giao thức BOOTP và DHCP, và giá trị timeout (số giây chờ trả lời sau khi gửi DHCP discover), số lần cố gắng nhận địa chì IP thông qua DHCP:
                                Code:
                                #define DHCP_UDP_SERVER_PORT	67	//UDP port where DHCP requests should be sent
                                #define DHCP_UDP_CLIENT_PORT	68	//UDP port clients will receive DHCP replies
                                //
                                #define DHCP_TIMEOUT	10
                                #define DHCP_RETRIES	3

                                Bây giờ ta mở file source và bắt đầu viết code:
                                Trước hết ta khai báo các biến sử dụng :
                                Code:
                                //--------------------------------------------------------------------------------------
                                unsigned long DhcpServerIP;
                                unsigned long DhcpTransactID;
                                unsigned long DhcpLeaseTime;
                                unsigned char macaddr[6];
                                //
                                unsigned char DhcpTimeout;
                                unsigned char DhcpRetries;
                                Viết hàm khởi tạo giao thức DHCP:
                                Code:
                                //--------------------------------------------------------------------------------------
                                //Ham khoi tao cac thong so ban dau cho DHCP
                                void dhcpInit(void)
                                {
                                	ethGetMacAddress(macaddr);
                                	DhcpTransactID = *((unsigned long*)&macaddr[0]);
                                	DhcpLeaseTime = 0;
                                	DhcpTimeout = 1;
                                	DhcpRetries = DHCP_RETRIES;
                                }
                                Hàm ghi giá trị vào trường option của DHCP, mỗi trường option sẽ bắt đầu bằng 1 byte option code, tiếp đến là 1 byte chiều dài của giá trị option, theo sau là các byte giá trị của option:
                                Code:
                                //--------------------------------------------------------------------------------------
                                //Ham set cac option cua DHCP
                                unsigned char* dhcpSetOption(unsigned char* options, unsigned char optcode, unsigned char optlen, void* optvalptr)
                                {
                                	*options++ = optcode;
                                	*options++ = optlen;
                                	while(optlen--)
                                	{
                                		*options++ = *(unsigned char*)optvalptr++;
                                	}
                                	*options = DHCP_OPT_END;
                                	return options;
                                }
                                Hàm đọc giá trị từ trường option vào 1 biến:
                                Code:
                                //--------------------------------------------------------------------------------------
                                //Ham lay cac option cua DHCP
                                unsigned char dhcpGetOption(unsigned char* options, unsigned char optcode, unsigned char optlen, void* optvalptr)
                                {
                                	unsigned char i;
                                	for (;;)
                                	{
                                		if(*options == DHCP_OPT_PAD)
                                			options++;
                                		else if(*options == DHCP_OPT_END)
                                			break;
                                		else if(*options == optcode)
                                		{
                                			optlen = ((optlen<*(options+1))?(optlen):(*(options+1)));
                                			for(i=0; i<optlen; i++)
                                				*(((uint8_t*)optvalptr)+i) = *(options+i+2);
                                			return *(options+1);
                                		}
                                		else
                                		{
                                			options++;
                                			options+=*options;
                                			options++;
                                		}
                                	}
                                	return 0;
                                }
                                Hàm xuất ra cổng serial Header của bản tin (dùng cho mục đích debug) :
                                Code:
                                //--------------------------------------------------------------------------------------
                                #ifdef DHCP_DEBUG
                                //Ham de in Header goi DHCP (de debug)
                                void dhcpPrintHeader(struct netDhcpHeader* packet)
                                {
                                	printf("DHCP Packet:\r\n");
                                	// print op
                                	printf("Op      : ");
                                	switch(packet->bootp.opcode)
                                	{
                                	case BOOTP_OP_BOOTREQUEST:	printf("BOOTREQUEST"); break;
                                	case BOOTP_OP_BOOTREPLY:	printf("BOOTREPLY"); break;
                                	default:					printf("UNKNOWN"); break;
                                	}
                                	printf("\n\r");
                                	// print transaction ID
                                	printf("XID     : 0x");	/*rprintfu32(packet->bootp.transid);*/				printf("\n\r");
                                	// print client IP address
                                	printf("ClIpAddr: ");	ipPrintAddr(HTONL(packet->bootp.clipaddr));	printf("\n\r");
                                	// print 'your' IP address
                                	printf("YrIpAddr: ");	ipPrintAddr(HTONL(packet->bootp.yoipaddr));	printf("\n\r");
                                	// print server IP address
                                	printf("SvIpAddr: ");	ipPrintAddr(HTONL(packet->bootp.seipaddr));	printf("\n\r");
                                	// print gateway IP address
                                	printf("GwIpAddr: ");	ipPrintAddr(HTONL(packet->bootp.gwipaddr));	printf("\n\r");
                                	// print client hardware address
                                	printf("ClHwAddr: ");	ethPrintAddr((struct ntEthAddr*)packet->bootp.clhwaddr);	printf("\n\r");
                                }
                                #endif
                                Hàm gửi đi bản tin DHCP discover :
                                Code:
                                //--------------------------------------------------------------------------------------
                                //Ham gui di mot ban tin DHCP discover de tim kiem DHCP server
                                void dhcpDiscover(void)
                                {
                                	struct netDhcpHeader* packet;
                                	unsigned long val;
                                	unsigned char* optptr;
                                	
                                	packet = (struct netDhcpHeader*)(ethGetBuffer() + ETH_HEADER_LEN + IP_HEADER_LEN + UDP_HEADER_LEN);
                                	//
                                	packet->bootp.opcode = BOOTP_OP_BOOTREQUEST;
                                	packet->bootp.hwaddrtype = BOOTP_HTYPE_ETHERNET;
                                	packet->bootp.hwaddrlen = BOOTP_HLEN_ETHERNET;
                                	packet->bootp.clipaddr = HTONL(ipGetConfig()->ip);
                                	packet->bootp.yoipaddr = HTONL(0l);
                                	packet->bootp.seipaddr = HTONL(0l);
                                	packet->bootp.gwipaddr = HTONL(0l);
                                	ethGetMacAddress(&packet->bootp.clhwaddr[0]);
                                	packet->bootp.transid = DhcpTransactID;
                                	packet->bootp.flags = HTONS(1);
                                	//
                                	packet->cookie = 0x63538263;
                                	val = DHCP_MSG_DHCPDISCOVER;
                                	optptr = dhcpSetOption(packet->options, DHCP_OPT_DHCPMSGTYPE, 1, &val);
                                	dhcpSetOption(optptr, DHCP_OPT_CLIENTID, 6, macaddr);
                                	#ifdef DHCP_DEBUG
                                	printf("DHCP: Sending Query\r\n");
                                	dhcpPrintHeader(packet);
                                	#endif
                                	udpSend(0xFFFFFFFF, DHCP_UDP_SERVER_PORT, DHCP_UDP_CLIENT_PORT, DHCP_HEADER_LEN+3+1+8, (unsigned char*)packet);
                                }
                                Hàm gửi bản tin DHCP request để đáp ứng lại cho DHCP offer :
                                Code:
                                //--------------------------------------------------------------------------------------
                                //Ham gui di mot ban tin DHCP request de yeu cau nhan dia chi IP
                                void dhcpRequest(struct netDhcpHeader* packet, unsigned long serverid)
                                {
                                	unsigned char* optptr;
                                	unsigned long val;
                                
                                	packet->bootp.opcode = BOOTP_OP_BOOTREQUEST;		// request type
                                	val = DHCP_MSG_DHCPREQUEST;
                                	optptr = dhcpSetOption(packet->options, DHCP_OPT_DHCPMSGTYPE, 1, &val);
                                	optptr = dhcpSetOption(optptr, DHCP_OPT_CLIENTID, 6, macaddr);
                                	optptr = dhcpSetOption(optptr, DHCP_OPT_SERVERID, 4, &serverid);
                                	optptr = dhcpSetOption(optptr, DHCP_OPT_REQUESTEDIP, 4, &packet->bootp.yoipaddr);
                                	((unsigned char*)&val)[0] = DHCP_OPT_NETMASK;
                                	((unsigned char*)&val)[1] = DHCP_OPT_ROUTERS;
                                	((unsigned char*)&val)[2] = DHCP_OPT_DNSSERVERS;
                                	((unsigned char*)&val)[3] = DHCP_OPT_DOMAINNAME;
                                	optptr = dhcpSetOption(optptr, DHCP_OPT_PARAMREQLIST, 4, &val);
                                	packet->bootp.yoipaddr = HTONL(0l);
                                	#ifdef DHCP_DEBUG
                                	printf("DHCP: Sending request in response to offer\r\n");
                                	#endif
                                	udpSend(0xFFFFFFFF, DHCP_UDP_SERVER_PORT, DHCP_UDP_CLIENT_PORT, DHCP_HEADER_LEN+3+6+6+6+8+1, (unsigned char*)packet);
                                }
                                Hàm xử lý gói DHCP nhận được, hàm này sẽ được gọi bởi giao thức UDP:
                                Code:
                                //--------------------------------------------------------------------------------------
                                //Ham xu ly mot goi DHCP nhan duoc
                                void dhcpIn(unsigned int len, struct netDhcpHeader* packet)
                                {
                                	unsigned char msgtype;
                                	unsigned long sid;
                                	unsigned long netmask;
                                	unsigned long gateway;
                                	unsigned long val;
                                	//
                                	#ifdef DHCP_DEBUG
                                	dhcpPrintHeader(packet);
                                	#endif
                                	//
                                	if((packet->bootp.opcode != BOOTP_OP_BOOTREPLY) || (packet->bootp.transid != DhcpTransactID))
                                		return;
                                	//
                                	dhcpGetOption(packet->options, DHCP_OPT_DHCPMSGTYPE, 1, &msgtype);
                                	#ifdef DHCP_DEBUG
                                	printf("DHCP: Received msgtype = %d\r\n", msgtype);
                                	#endif
                                	//
                                	if(msgtype == DHCP_MSG_DHCPOFFER)
                                	{
                                		dhcpGetOption(packet->options, DHCP_OPT_SERVERID, 4, &sid);
                                		#ifdef DHCP_DEBUG
                                		printf("DHCP: Got offer from server "); ipPrintAddr(HTONL(sid)); printf("\n\r");
                                		#endif
                                		dhcpRequest(packet, sid);
                                	}
                                	//
                                	else if(msgtype == DHCP_MSG_DHCPACK)
                                	{
                                		dhcpGetOption(packet->options, DHCP_OPT_NETMASK, 4, &val);
                                		netmask = HTONL(val);
                                		//
                                		dhcpGetOption(packet->options, DHCP_OPT_ROUTERS, 4, &val);
                                		gateway = HTONL(val);
                                		//
                                		dhcpGetOption(packet->options, DHCP_OPT_LEASETIME, 4, &val);
                                		DhcpLeaseTime = HTONL(val);
                                		//
                                		ipSetConfig(HTONL(packet->bootp.yoipaddr), netmask, gateway);
                                		//
                                		DhcpRetries = 0;
                                		#ifdef DHCP_DEBUG
                                		printf("DHCP: Got request ACK, bind complete\r\n");
                                		ipPrintConfig(ipGetConfig());
                                		printf("LeaseTm : %d\n\r", DhcpLeaseTime);
                                		#endif
                                	}
                                }
                                Hàm hủy bỏ địa chỉ IP hiện tại:
                                Code:
                                //--------------------------------------------------------------------------------------
                                //Ham release dia chi IP hien tai va xoa cac thong so cau hinh IP dang co
                                void dhcpRelease(void)
                                {
                                	struct netDhcpHeader* packet;
                                	unsigned long val;
                                	unsigned char* optptr;
                                	//
                                	packet = (struct netDhcpHeader*)&ethGetBuffer()[ETH_HEADER_LEN+IP_HEADER_LEN+UDP_HEADER_LEN];
                                	//
                                	packet->bootp.opcode = BOOTP_OP_BOOTREQUEST;
                                	packet->bootp.hwaddrtype = BOOTP_HTYPE_ETHERNET;
                                	packet->bootp.hwaddrlen = BOOTP_HLEN_ETHERNET;
                                	packet->bootp.clipaddr = HTONL(ipGetConfig()->ip);
                                	packet->bootp.yoipaddr = HTONL(0l);
                                	packet->bootp.seipaddr = HTONL(0l);
                                	packet->bootp.gwipaddr = HTONL(0l);
                                	ethGetMacAddress(&packet->bootp.clhwaddr[0]);
                                	packet->bootp.transid = DhcpTransactID;
                                	packet->bootp.flags = HTONS(1);
                                	//
                                	packet->cookie = 0x63538263;
                                	//
                                	val = DHCP_MSG_DHCPRELEASE;
                                	optptr = dhcpSetOption(packet->options, DHCP_OPT_DHCPMSGTYPE, 1, &val);
                                	//
                                	val = HTONL(DhcpServerIP);
                                	optptr = dhcpSetOption(optptr, DHCP_OPT_SERVERID, 4, &val);
                                	//
                                	optptr = dhcpSetOption(optptr, DHCP_OPT_REQUESTEDIP, 4, &packet->bootp.clipaddr);
                                	//
                                	#ifdef DHCP_DEBUG
                                	printf("DHCP: Sending Release to "); ipPrintAddr(DhcpServerIP); printf("\n\r");
                                	#endif
                                	udpSend(DhcpServerIP, DHCP_UDP_SERVER_PORT, DHCP_UDP_CLIENT_PORT, DHCP_HEADER_LEN+3+6+6+1, (unsigned char*)packet);
                                	ipSetConfig(0,0,0);
                                	DhcpLeaseTime = 0;
                                }
                                Hàm cập nhật các biến thời gian mà DHCP sử dụng (được gọi 1s/lần bởi timer):
                                Code:
                                //--------------------------------------------------------------------------------------
                                //Ham duoc goi dinh ky moi 1s de cap nhat lease time va timeout cua DHCP
                                void dhcpTimer(void)
                                {
                                	// this function to be called once per second
                                	// decrement lease time
                                	if(DhcpLeaseTime)
                                		DhcpLeaseTime--;
                                	if(DhcpTimeout){
                                		DhcpTimeout--;
                                	}
                                }
                                Hàm dịch vụ DHCP, ta sẽ đưa vào vòng lặp chương trình chính:
                                Code:
                                //--------------------------------------------------------------------------------------
                                //Ham dich vu DHCP, duoc goi trong chuong trinh chinh
                                void dhcpService(void)
                                {
                                	if(DhcpRetries && (DhcpTimeout == 0)){
                                		DhcpRetries--;
                                		DhcpTimeout = DHCP_TIMEOUT;
                                		dhcpDiscover();
                                	}
                                }
                                //--------------------------------------------------------------------------------------
                                Vậy là xong file source và header cho DHCP, các bạn nhớ thêm khai báo hàm vào file header nhé .
                                Last edited by nttam79; 16-11-2011, 10:45.

                                Comment

                                Về tác giả

                                Collapse

                                nttam79 Tìm hiểu thêm về nttam79

                                Bài viết mới nhất

                                Collapse

                                Đang tải...
                                X