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

  • #91
    Tiếp theo, để có thể chạy thử giao thức DHCP, chúng ta cần modify source cũ một tí để bổ sung giao thức này vào:

    1-Mở file “timer.h” sửa define cho prescale của timer thành 1024 để timer chạy đúng, ngắt 1s/lần (với thạch anh 12MHz nha các bạn):
    Code:
    #define TIMER1PRESCALE		TIMER_CLK_DIV1024
    2-Mở file “udp.c”, sửa hàm udpSend để bổ sung source port vào trong hàm, thêm lệnh gọi hàm của giao thức DHCP vào hàm UDPProcess:
    Code:
    //----------------------------------------------------------------------------
    // Writen by NTTam - PTITHCM
    //----------------------------------------------------------------------------
    #include "packet.h"
    #include "ip.h"
    #include "uart.h"
    #include "dhcp.h"
    //#define UDP_DEBUG
    //----------------------------------------------------------------------------
    //Ham gui di mot goi UDP
    void udpSend(unsigned long dstIp, unsigned int dstPort, unsigned int srcPort, unsigned int len, unsigned char* udpData)
    {
    	struct ntUDPHeader* udpHeader;
    	udpHeader = (struct ntUDPHeader*)(udpData - UDP_HEADER_LEN);
    	len += UDP_HEADER_LEN;
    	udpHeader->desPort = HTONS(dstPort);
    	udpHeader->srcPort  = HTONS(srcPort);
    	udpHeader->Len = HTONS(len);
    	udpHeader->Checksum = 0;
    	ipSend(dstIp, IP_PROTO_UDP, len, (unsigned char*)udpHeader);
    }
    //--------------------------------------------------------------------------------------
    //Ham xu ly goi UDP nhan duoc, duoc goi boi ham xu ly goi IP (IPProcess)
    // Hien chua co ung dung chay UDP nen ham nay trong
    void UDPProcess(unsigned int len, struct ntIPHeader* packet)
    {
    	dhcpIn((len - IP_HEADER_LEN - UDP_HEADER_LEN), (struct netDhcpHeader*)((char*)packet + IP_HEADER_LEN + UDP_HEADER_LEN));
    	#ifdef UDP_DEBUG
    	printf("Rx UDP Packet\r\n");
    	#endif
    }
    //--------------------------------------------------------------------------------------
    (Nhớ cập nhật khai báo hàm bên file header nha)

    3-Thêm một số include (khi dịch báo lỗi thì các bạn cũng tự tìm ra mà thêm vào thôi, chỉ luôn cho đỡ mắc công kiếm):
    #include <avr/pgmspace.h>//// vào “tcp.h”
    #include "dhcp.h"//// vào “ntAVRnet.h”
    #include "udp.h" và #include "icmp.h" vào “ip.h”

    4-Sửa hàm IPProcess, thêm các lệnh gọi hàm của giao thức UDP, TCP vào:
    Code:
    void IPProcess(unsigned int len, struct ntIPHeader* packet)
    {
    	// check IP addressing, stop processing if not for me and not a broadcast
    	if( (HTONL(packet->desIPAddr) != ipGetConfig()->ip) &&
    		(HTONL(packet->desIPAddr) != (ipGetConfig()->ip|ipGetConfig()->netmask)) &&
    		(HTONL(packet->desIPAddr) != 0xFFFFFFFF) &&
    		(ipGetConfig()->ip != 0x00000000) ) 
    		return;
    
    	// handle ICMP packet
    	if( packet->Protocol == IP_PROTO_ICMP )
    	{
    		#ifdef IP_DEBUG
    		printf("IP->Rx: ICMP/IP packet\r\n");
    		//icmpPrintHeader((icmpip_hdr*)packet);
    		#endif
    		icmpIpIn((struct ntIPHeader*)packet);
    	}
    	else if( packet->Protocol == IP_PROTO_UDP )
    	{
    		#ifdef IP_DEBUG
    		printf("IP->Rx: UDP/IP packet\r\n");
    		//debugPrintHexTable(NetBufferLen-14, &NetBuffer[14]);
    		#endif
    		UDPProcess(len, ((struct ntIPHeader*)packet) );////
    	}
    	else if( packet->Protocol == IP_PROTO_TCP )
    	{
    		#ifdef IP_DEBUG
    		printf("IP->Rx: TCP/IP packet\r\n");
    		#endif
    		TCPProcess((unsigned char *)packet,len-((packet->verHdrLen & 0x0F)<<2));////
    	}
    	else
    	{
    		#ifdef IP_DEBUG
    		printf("IP->Rx: IP packet\r\n");
    		#endif
    	}
    }
    //--------------------------------------------------------------------------------------
    5-Mở hàm ngắt timer 1 (trong file timer.h), thêm vào các hàm cập nhật thời gian của giao thức TCP và DHCP vào:
    Code:
    TIMER_INTERRUPT_HANDLER(SIG_OVERFLOW1)
    {
    	//Tai nap gia tri timer 1
    	TCNT1 = 0xFFFF - TIMER1_INTERVAL;
    	//Cap nhat watchdog timer
    	if((time_watchdog++) > 120){
            time_watchdog = 0;
            ethInit();
    	}
    	Counter1s++;
    	arpTimer();
    	TCPCheckTimeOut();////
    	dhcpTimer();////
    }
    6-Thêm vào hàm main trong file “ntAVRnet.h”
    Code:
    int	main()
    {
    	SystemInit();
    	printf("\r\nNTTam AVR network testing with enc28j60.\r\n");
    	printf("Initializing Network Interface and Stack\r\n");
    	printf("Ethernet chip init\r\n");
    	IpMyConfig.ethaddr.addr[0] = ETHADDR0;
    	IpMyConfig.ethaddr.addr[1] = ETHADDR1;
    	IpMyConfig.ethaddr.addr[2] = ETHADDR2;
    	IpMyConfig.ethaddr.addr[3] = ETHADDR3;
    	IpMyConfig.ethaddr.addr[4] = ETHADDR4;
    	IpMyConfig.ethaddr.addr[5] = ETHADDR5;
    	IpMyConfig.ip = IPADDRESS;
    	IpMyConfig.netmask = NETMASK;
    	IpMyConfig.gateway = GATEWAY;
    	netInit(IpMyConfig.ip, IpMyConfig.netmask, IpMyConfig.gateway);
    	PrintIPConfig();
    	printf("Getting IP Address....\r\n");
    	if(IpMyConfig.ip == 0x00000000){
    		dhcpInit();
    	}
    	while(1)
    	{
    		ethService();
    		dhcpService();
    	}
    	return 0;
    }
    Bây giờ nếu lúc đầu mạch của ta chưa có địa chỉ IP (IP address là 0.0.0.0) thì nó sẽ khởi tạo giao thức DHCP để nhận địa chỉ IP.
    Để thử, ta chỉnh lại các thông số cấu hình IP trong file “ntAVRnet.h” như sau:
    Code:
    #define IPDOT(a,b,c,d)	((unsigned long)((unsigned char)a)<<24)+((unsigned long)((unsigned char)b)<<16)+((unsigned long)((unsigned char)c)<<8)+(unsigned char)d//((a<<24)|(b<<16)|(c<<8)|(d))
    //#define IPADDRESS			IPDOT(192,168,1,10)
    #define IPADDRESS			IPDOT(0,0,0,0)
    #define NETMASK				IPDOT(0,0,0,0)
    #define GATEWAY				IPDOT(0,0,0,0)
    Bây giờ ta có thể biên dịch, nối cáp mạng và mở nguồn, đợi board nhận địa chỉ IP (nhớ kết nối cổng COM để còn biết nó nhận được địa chỉ bao nhiêu nhé).
    Phần code này chỉ khởi động DHCP lúc mới reset mạch thôi nhé, chưa hỗ trợ hot plug cáp mạng . Các bạn có thể tự sửa code để thêm phần này vào.

    Comment


    • #92
      Em biết cái lách luật đó là gì rồi.Khi destination mac address là FF:FF:FF:FF:FF:FF thì thằng modem ADSL hay gateway nó cũng nhận được gói tin này và điều quan trọng gateway chỉ xử lý lớp ip nên có thể gửi ra ngoài mạng Lan.
      , , ,

      Comment


      • #93
        Nguyên văn bởi rptdnmqs Xem bài viết
        Em biết cái lách luật đó là gì rồi.Khi destination mac address là FF:FF:FF:FF:FF:FF thì thằng modem ADSL hay gateway nó cũng nhận được gói tin này và điều quan trọng gateway chỉ xử lý lớp ip nên có thể gửi ra ngoài mạng Lan.
        rptdnmqs có biết tại sao phải làm như vậy không?

        Comment


        • #94
          Có phải thầy đang nói đến việc mà MAC của gateway có thể trÙng với địa chỉ MAC của 1 máy nào đó trong mạng LAN.Dẫn đến gửi gói tin thất bại.Nên phải dÙng gói broadcast.
          , , ,

          Comment


          • #95
            Nguyên văn bởi nttam79 Xem bài viết
            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.
            Hình minh họa thật là dễ hiểu wa. Thanks !
            Cho em hỏi thêm là:1- Khi gói tin được gởi ra khỏi modem ADSL đến router biên thì lúc này các router chỉ cần dựa vào bảng định tuyến mà chuyển tiếp dữ liệu hay là có cần thêm địa chỉ MAC gì không.
            2- IP WAN 123.20.165.7 có ý nghĩa gì trong quá trình gởi data không.
            3- Khi một máy tính trên internet muốn truy cập vào mạch AVRnet của mình thì phải gõ //ip là bao nhiêu vậy.

            Email:
            Tel: 0983.497.310

            Comment


            • #96
              Nguyên văn bởi tienhuypro Xem bài viết
              Cho em hỏi thêm là:
              1- Khi gói tin được gởi ra khỏi modem ADSL đến router biên thì lúc này các router chỉ cần dựa vào bảng định tuyến mà chuyển tiếp dữ liệu hay là có cần thêm địa chỉ MAC gì không.
              2- IP WAN 123.20.165.7 có ý nghĩa gì trong quá trình gởi data không.
              3- Khi một máy tính trên internet muốn truy cập vào mạch AVRnet của mình thì phải gõ //ip là bao nhiêu vậy.
              1-Tất cả các router, không riêng gì router biên, lõi hay router khách hàng, đều chỉ dựa vào bảng định tuyến để chuyển dữ liệu đi, router không quan tâm đến địa chỉ MAC. Chính vì vậy router được xem là thiết bị lớp 3 (lớp network).
              2-Có một điều cần lưu ý là địa chỉ IP 192.168.1.x chỉ là địa chỉ local cho mạng LAN, bên ngoài chỉ biết tới chúng ta qua địa chỉ IP WAN, khi gói tin ra mạng internet, nếu trong trường Source IP Address vẫn để địa chỉ này, thì máy tính trên mạng Internet khi trả lời sẽ trả lời theo địa chỉ này thì sẽ không tới được router ADSL của chúng ta. Vi vậy trước khi Router ADSL chuyển gói tin đi ra mạng WAN, nó sẽ thay địa chỉ Source IP Address trong header IP bằng địa chỉ IP WAN của nó (123.20.165.7). Như vậy khi máy tính trên Internet nhận được và trả lời theo địa chỉ này, Router ADSL sẽ nhận được, trước khi chuyển gói tin vào bên trong mạng LAN, nó thay trở lại bằng địa chỉ Local (192.168.1.x). Hoạt động này gọi là NAT (Network Address Translate) mà bạn ding_dong có lần nhắc tới nhưng tôi chưa có dịp nói chi tiết.
              3-Từ Internet, muốn truy cập vào mạch của chúng ta tất nhiên phải truy cập tới địa chỉ IP WAN (gõ http://123.20.165.7). Khi đó trong modem ADSL ta cần khai báo để nó chuyển mọi truy cập HTTP tới địa chỉ IP WAN sang cho mạch AVRnet (đó chính là phần cấu hình modem, sẽ hướng dẫn cuối cùng).

              Comment


              • #97
                Code:
                void arpIpOut(unsigned char* ethFrame, unsigned long phyDstIp)
                {
                	unsigned char index;
                	struct ntEthHeader* ethHeader;
                	struct ntIPHeader* ipHeader;
                	ethHeader = (struct ntEthHeader*)ethFrame;
                	ipHeader = (struct ntIPHeader*)(ethFrame + ETH_HEADER_LEN);
                
                	if(phyDstIp)
                		index = arpSearchIP(phyDstIp);
                	else
                		index = arpSearchIP(HTONL(ipHeader->desIPAddr));
                	if(index < ARP_TABLE_SIZE)
                	{
                		ethHeader->srcAddr  = ARPMyAddr.ethAddr;
                		ethHeader->desAddr = ARPTable[index].ethAddr;
                		ethHeader->type = HTONS(ETH_TYPE_IP);
                	}
                	else
                	{
                		ethHeader->srcAddr = ARPMyAddr.ethAddr;
                		ethHeader->desAddr.addr[0] = 0xFF;
                		ethHeader->desAddr.addr[1] = 0xFF;
                		ethHeader->desAddr.addr[2] = 0xFF;
                		ethHeader->desAddr.addr[3] = 0xFF;
                		ethHeader->desAddr.addr[4] = 0xFF;
                		ethHeader->desAddr.addr[5] = 0xFF;
                		ethHeader->type = HTONS(ETH_TYPE_IP);
                	}
                	#ifdef ARP_DEBUG
                	printf("ARP Result:");
                	ipPrintAddr(ARPTable[index].ipAddr);printf("-");
                	ethPrintAddr(&(ethHeader->desAddr));printf("\r\n");
                	#endif
                }
                Anh Tâm có hỏi
                " Trong hàm ArpIpOut trên, có 1 chỗ "lách luật", không tuân thủ đúng nguyên tắc làm việc của ARP, đố các bạn tìm ra, nếu có ai tìm ra mình sẽ giải thích tại sao lại làm như vậy."

                Hôm nay mới đọc code của anh Tâm viết và đến đây thấy anh Tâm hỏi rất hay nên tìm hiểu và trả lời thế này, có gì anh Tâm chỉnh nha.
                - Trong hàm ArpIpOut dò tìm địa chỉ MAC ứng với IP trong bảng ARP cache mà thằng IP nó hỏi. Nếu trong bảng ARP cache ( bảng này <=8 trong project) không có IP tương ứng, hay bảng ARP cache chưa được cập nhật đầy đủ thì theo cách giải quyết của giao thức ARP là nó sẽ gởi đi một gới tin có tên là ARP request chứa IP mà nó cần tìm dưới dạng broadcast trong mạng LAN "Ai là người có địa chỉ IP a.b.c.d ?" để máy tính nào có địa chỉ IP trên sẽ trả lời bằng bản tin ARP reply.
                - Tuy nhiên trong code của anh Tâm thì ARP không gởi gói tin ARP request mà điền luôn địa chỉ MAC đích là FF.FF.FF.FF.FF.FF vào trong gói IP, và lẽ dĩ nhiên là gói tin này sẽ gởi đến tất cả các máy trong mạng LAN nhưng thằng nào có IP đúng thì mới nhận được vì ở giao thức IP sẽ kiểm tra lại IP gói được gởi tới có phải là của mình hay không.
                - Như chúng ta biết bảng ARP cache được cập nhật là có 2 trường hợp. 1- là gởi bản tin ARP request, 2- mỗi khi có gói tin IP đến thì nó sẽ cập nhật IP và MAC của thằng máy tính đã gởi đi. Cứ như thế nếu thằng nào gởi thì nó sẽ tự cập nhât IP và MAC vào bảng ARP cache thôi.

                Không biết Huy nói thế có đúng không nữa vì gà mà. Hehe có gì anh Tâm chỉnh lại em nhé. Thanks!

                Email:
                Tel: 0983.497.310

                Comment


                • #98
                  Nguyên văn bởi tienhuypro Xem bài viết
                  Code:
                  void arpIpOut(unsigned char* ethFrame, unsigned long phyDstIp)
                  {
                  	unsigned char index;
                  	struct ntEthHeader* ethHeader;
                  	struct ntIPHeader* ipHeader;
                  	ethHeader = (struct ntEthHeader*)ethFrame;
                  	ipHeader = (struct ntIPHeader*)(ethFrame + ETH_HEADER_LEN);
                  
                  	if(phyDstIp)
                  		index = arpSearchIP(phyDstIp);
                  	else
                  		index = arpSearchIP(HTONL(ipHeader->desIPAddr));
                  	if(index < ARP_TABLE_SIZE)
                  	{
                  		ethHeader->srcAddr  = ARPMyAddr.ethAddr;
                  		ethHeader->desAddr = ARPTable[index].ethAddr;
                  		ethHeader->type = HTONS(ETH_TYPE_IP);
                  	}
                  	else
                  	{
                  		ethHeader->srcAddr = ARPMyAddr.ethAddr;
                  		ethHeader->desAddr.addr[0] = 0xFF;
                  		ethHeader->desAddr.addr[1] = 0xFF;
                  		ethHeader->desAddr.addr[2] = 0xFF;
                  		ethHeader->desAddr.addr[3] = 0xFF;
                  		ethHeader->desAddr.addr[4] = 0xFF;
                  		ethHeader->desAddr.addr[5] = 0xFF;
                  		ethHeader->type = HTONS(ETH_TYPE_IP);
                  	}
                  	#ifdef ARP_DEBUG
                  	printf("ARP Result:");
                  	ipPrintAddr(ARPTable[index].ipAddr);printf("-");
                  	ethPrintAddr(&(ethHeader->desAddr));printf("\r\n");
                  	#endif
                  }
                  Anh Tâm có hỏi
                  " Trong hàm ArpIpOut trên, có 1 chỗ "lách luật", không tuân thủ đúng nguyên tắc làm việc của ARP, đố các bạn tìm ra, nếu có ai tìm ra mình sẽ giải thích tại sao lại làm như vậy."

                  Hôm nay mới đọc code của anh Tâm viết và đến đây thấy anh Tâm hỏi rất hay nên tìm hiểu và trả lời thế này, có gì anh Tâm chỉnh nha.
                  - Trong hàm ArpIpOut dò tìm địa chỉ MAC ứng với IP trong bảng ARP cache mà thằng IP nó hỏi. Nếu trong bảng ARP cache ( bảng này <=8 trong project) không có IP tương ứng, hay bảng ARP cache chưa được cập nhật đầy đủ thì theo cách giải quyết của giao thức ARP là nó sẽ gởi đi một gới tin có tên là ARP request chứa IP mà nó cần tìm dưới dạng broadcast trong mạng LAN "Ai là người có địa chỉ IP a.b.c.d ?" để máy tính nào có địa chỉ IP trên sẽ trả lời bằng bản tin ARP reply.
                  - Tuy nhiên trong code của anh Tâm thì ARP không gởi gói tin ARP request mà điền luôn địa chỉ MAC đích là FF.FF.FF.FF.FF.FF vào trong gói IP, và lẽ dĩ nhiên là gói tin này sẽ gởi đến tất cả các máy trong mạng LAN nhưng thằng nào có IP đúng thì mới nhận được vì ở giao thức IP sẽ kiểm tra lại IP gói được gởi tới có phải là của mình hay không.
                  - Như chúng ta biết bảng ARP cache được cập nhật là có 2 trường hợp. 1- là gởi bản tin ARP request, 2- mỗi khi có gói tin IP đến thì nó sẽ cập nhật IP và MAC của thằng máy tính đã gởi đi. Cứ như thế nếu thằng nào gởi thì nó sẽ tự cập nhât IP và MAC vào bảng ARP cache thôi.

                  Không biết Huy nói thế có đúng không nữa vì gà mà. Hehe có gì anh Tâm chỉnh lại em nhé. Thanks!
                  Huy tìm ra rất đúng chỗ, rptdnmqs cũng đã tìm ra nhưng chưa nói đúng nguyên nhân phải làm như vậy.

                  Lý do phải làm vậy là: khi giao thức IP nhận được yêu cầu gửi gói tin đi thì dữ liệu ứng dụng đã nằm sẵn trên buffer dành cho frame ethernet rồi (ethFrame). Lúc này muốn gửi đi bản tin ARP request theo "đúng luật", ta phải tạo ra một buffer mới cho bản tin ARP request sẽ gửi đi, vì nếu không sẽ ghi đè lên dữ liệu ứng dụng. Nhưng bộ nhớ RAM của ATmega 32 nhỏ quá (có 2K) nên không đủ chỗ, vì vậy buộc phải "lách luật" thôi, hehe.

                  Comment


                  • #99
                    Nguyên văn bởi nttam79 Xem bài viết
                    Huy tìm ra rất đúng chỗ, rptdnmqs cũng đã tìm ra nhưng chưa nói đúng nguyên nhân phải làm như vậy.

                    Lý do phải làm vậy là: khi giao thức IP nhận được yêu cầu gửi gói tin đi thì dữ liệu ứng dụng đã nằm sẵn trên buffer dành cho frame ethernet rồi (ethFrame). Lúc này muốn gửi đi bản tin ARP request theo "đúng luật", ta phải tạo ra một buffer mới cho bản tin ARP request sẽ gửi đi, vì nếu không sẽ ghi đè lên dữ liệu ứng dụng. Nhưng bộ nhớ RAM của ATmega 32 nhỏ quá (có 2K) nên không đủ chỗ, vì vậy buộc phải "lách luật" thôi, hehe.
                    WOU ! em không nghĩ tới chỗ bộ nhớ RAM 2K của Mega32. Thanks anh
                    Nhưng em nghĩ giải thuật kiểu này cũng hay, đỡ phải gởi đi gởi lại tốn CALO nhỉ. hehe
                    Anh Tâm cho em hỏi cái này nữa:
                    1- Nếu mình set 2 mạch cùng MAC cùng IP thì sẽ xảy ra chuyện gì nhỉ.
                    2- Em nạp chương trình vào mạch tới đoạn mà Ping được như hôm trước (em dùng cáp chéo cắm trực tiếp từ Board đến máy tính), lúc mới cắm điện vào mạch Ping thì OK nhưng để một lúc như mình lướt web hay làm cái gì liên quan đến internet trên máy tính thì Ping lại không được nữa mặc dù đã nhấn nút reset cứng trên mạch. Lỗi này là do tràn bộ nhớ ENC hay treo chương trình VĐK hả anh.
                    Last edited by tienhuypro; 17-11-2011, 13:55.

                    Email:
                    Tel: 0983.497.310

                    Comment


                    • anh tam sửa giúp em nốt cái lỗi này với.để em có thể có bản dịch demo có thể chạy được
                      lỗi là: :Error [1099] Invalid MAX_TCP_SOCKETS value specified.
                      đây là project em đang sửa đến lỗi đó:

                      down:pic18f4620.402-fix.rar
                      cám ơn anh nhiều!

                      Comment


                      • Nguyên văn bởi kiemkhach10 Xem bài viết
                        anh tam sửa giúp em nốt cái lỗi này với.để em có thể có bản dịch demo có thể chạy được
                        lỗi là: :Error [1099] Invalid MAX_TCP_SOCKETS value specified.
                        đây là project em đang sửa đến lỗi đó:

                        down:pic18f4620.402-fix.rar
                        cám ơn anh nhiều!
                        Có sửa lỗi đó thì sẽ lại có lỗi khác thôi, quan trọng là bạn phải sửa lại các define trong HardwareProfile và các file config có liên quan cho phù hợp với hardware của mình, nếu không có biên dịch thành công thì nạp vào mạch cũng không chạy.

                        Nếu bạn chỉ muốn biên dịch được 1 cái cho có khí thế tiếp tục thì có thể sửa các define như sau:
                        thêm vào TCPIPconfig.h:
                        Code:
                        #define MAX_TCP_SOCKETS     (8ul)
                        #define TCP_TX_FIFO_SIZE	(200ul)
                        #define TCP_RX_FIFO_SIZE	(200ul)
                        #define MAX_UDP_SOCKETS     (8ul)
                        #define MAX_HTTP_CONNECTIONS	(3ul)
                        
                        #define MY_DEFAULT_HOST_NAME			"OLIMEX BOARD"
                        #define MY_DEFAULT_MAC_BYTE6            (0x00)
                        #define MY_DEFAULT_IP_ADDR_BYTE4        (94ul)
                        Thêm vào HardwareProfile.h:
                        Code:
                        #define OLIMEX_HW
                        Chúc thành công
                        Last edited by nttam79; 19-11-2011, 13:46.

                        Comment


                        • cám ơn anh!
                          trong phần #define có mấy cái (8ul),(200ul)... nghĩa là gì nhỉ?và ul có nghĩa là gì nhỉ?
                          cám ơn!

                          Comment


                          • Chào các Bác ! Mình có vài lời tâm sự thế này.
                            TUT này đã được 160 cảm ơn rồi. Có thể nói là từ khi mình đọc các bài viết trên diễn đàn thì bài viết của anh Tâm là một trong những bài viết chi tiết, công phu, rõ ràng và chất lượng nhất, được nhiều bạn cũng như tôi quan tâm và học hỏi rất nhiều. Huy thấy khi anh Tâm viết TUT này thì có rất nhiều bạn hỏi về đề tài tương tự như trên PIC hay FPGA và được anh Tâm trả lời rất nhiệt tình. Vì thế, mỗi khi bạn nào học được từ những kiến thức mà anh Tâm chia sẽ hay cảm thấy là hữu ích cho mình nên nhấn "thanks" nha. Huy không nói cách gượng ép đâu mà luôn xem làm điều này để khuyến khích cho diễn đàn dtvn ngày càng có nhiều bài viết hay như thế này.
                            TUT này cũng gần đến hồi kết rồi mình nghĩ chắc nhiều bạn cũng đã đạt được cái gì đó từ các bài viết này như mạch, hay là có bạn chuyển code sang AVRcodevison. Hy vọng khi TUT này của anh Tâm kết thúc thì cũng có nhiều project riêng cho bản thân liên quan đến TCP/IP của các bạn hay của mình sẽ Port tiếp lên TUT này để nó luôn được trang 1 của diễn đàn dtvn nhé các bạn.

                            Email:
                            Tel: 0983.497.310

                            Comment


                            • Nguyên văn bởi tienhuypro Xem bài viết
                              Anh Tâm cho em hỏi cái này nữa:
                              1- Nếu mình set 2 mạch cùng MAC cùng IP thì sẽ xảy ra chuyện gì nhỉ.
                              2- Em nạp chương trình vào mạch tới đoạn mà Ping được như hôm trước (em dùng cáp chéo cắm trực tiếp từ Board đến máy tính), lúc mới cắm điện vào mạch Ping thì OK nhưng để một lúc như mình lướt web hay làm cái gì liên quan đến internet trên máy tính thì Ping lại không được nữa mặc dù đã nhấn nút reset cứng trên mạch. Lỗi này là do tràn bộ nhớ ENC hay treo chương trình VĐK hả anh.
                              1- Nếu 2 mạch set cùng địa chỉ MAC và IP thì khi gửi đến địa chỉ IP này, cả 2 mạch cùng nhận được, các host khác sẽ xem như chỉ biết có 1 mạch trên LAN. Tuy nhiên khi hoạt động sẽ xảy ra lỗi: vì khi 1 máy khác truy cập theo địa chỉ đó, hai mạch sẽ cùng trả lời, điều này sẽ có thể dẫn đến giao thức TCP sẽ không thiết lập kết nối được do máy tính truy cập sẽ nhận được nhiều bản tin SYN (và có thể có số sequence number khác nhau nếu ta dùng cơ chế đánh sequence number theo thời gian). Kết quả là không truy cập webserver được.

                              2-Thỉnh thoảng anh cũng nhận thấy hiện tượng này và debug thử nhưng chưa tìm ra lý do. Có thể do chip ENC treo hoặc do ta quản lý bộ nhớ AVR chưa tốt. Như lúc viết giao thức ethernet anh có nói là sử dụng biến watchdog timer để reset ENC mỗi khi nó bị treo, dùng giải pháp này sẽ khắc phục được tình trạng đó, mạch chạy ổn định hơn rất nhiều. Nhưng thú thực là anh chưa tìm ra được nguồn gốc của vấn đề. Có lẽ phải dành tg tìm hiểu phần cứng ENC28J60 và debug thì mới biết được. Nếu có thời gian Huy thử nghiên cứu vấn đề này xem thử nhé.

                              Comment


                              • Nguyên văn bởi kiemkhach10 Xem bài viết
                                cám ơn anh!
                                trong phần #define có mấy cái (8ul),(200ul)... nghĩa là gì nhỉ?và ul có nghĩa là gì nhỉ?
                                cám ơn!
                                ul = unsigned long
                                cái này chỉ có ý nghĩa giúp trình biên dịch (complier) tính toán đúng khi biên dịch, không phải là khai báo kiểu biến.

                                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