最近要用到raw socket, 来看下。server.cpp:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <linux/if_ether.h>
#include <stdlib.h>
#include <arpa/inet.h>

int main()
{     
	printf("main is running\n");

    int iSock, nRead, iProtocol;        
    char buffer[4096] = {0};
    char  *ethhead, *iphead, *tcphead, *udphead, *icmphead, *p;
        
	if((iSock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP))) < 0)
    {
        printf("create iSocket error, check root\n");  // 需要root权限, 最后运行的时候, 可以用sudo ./server
        return 1;
    }
	        
	while(1) 
	{
		nRead = recvfrom(iSock, buffer, 2048, 0, NULL, NULL);  
		/*
			以太网帧头 14
			ip头       20
			udp头      8
			总共42字节(最少)
		*/
		if(nRead < 42) 
		{
			printf("packet error\n");
			continue;
		}
	        	
		int n = 0XFF;
		char szVisBuf[1024] = {0};
		for(unsigned int i = 0; i < nRead; ++i)
		{
			char szTmp[3] = {0};
			sprintf(szTmp, "%02x", buffer[i]&n);
			strcat(szVisBuf, szTmp);
		}
			
		
		ethhead = buffer;
		p = ethhead;
		
		iphead = ethhead + 14;  
		p = iphead + 12;

		char szIps[128] = {0};
		snprintf(szIps, sizeof(szIps), "IP: %d.%d.%d.%d => %d.%d.%d.%d",
			p[0]&n, p[1]&n, p[2]&n, p[3]&n,
			p[4]&n, p[5]&n, p[6]&n, p[7]&n);
		iProtocol = (iphead + 9)[0];
		p = iphead + 20;
		
		
		unsigned int iDstPort = (p[2]<<8)&0xff00 | p[3]&n;
		switch(iProtocol)
		{
			case IPPROTO_UDP : 
				if(iDstPort == 8888)
				{
					printf("source port: %u,",(p[0]<<8)&0xff00 |  p[1]&n);
					printf("dest port: %u\n", iDstPort);
					
					printf("%s\n", szIps);	
					printf("%s\n", szVisBuf);
					printf("nRead is %d\n", nRead);	
					
				}
				break;
			case IPPROTO_RAW : 
				printf("raw\n");
				break;
			default:
				break;
		}
	}
}

       启动它。

 

      client.cpp:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

int main()
{
    struct sockaddr_in srvAddr;
    bzero(&srvAddr, sizeof(srvAddr));
    srvAddr.sin_family = AF_INET;
    srvAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
    srvAddr.sin_port = htons(8888);

    int iSock = socket(AF_INET, SOCK_DGRAM, 0); // udp
	int i = 0;
    while(1)
    {
		printf("press enter to send data\n");
		getchar(); // 卡住
		char szBuf[32] = {0};
        snprintf(szBuf, sizeof(szBuf), "hello %d", ++i);
        sendto(iSock, szBuf, strlen(szBuf) + 1, 0, (struct sockaddr *)&srvAddr, sizeof(srvAddr));
    }

	close(iSock);
    return 0;
}

       向server发包。

 

       抓包结果:

13:59:37.865687  In 00:00:00:00:00:00 ethertype IPv4 (0x0800), length 53: 127.0.0.1.49574 > 127.0.0.1.8888: UDP, length 9
        0x0000:  0000 0304 0006 0000 0000 0000 0000 0800  ................
        0x0010:  4500 0025 a3b1 4000 4011 9914 7f00 0001  E..%..@.@.......
        0x0020:  7f00 0001 c1a6 22b8 0011 fe24 6865 6c6c  ......"....$hell
        0x0030:  6f20 3437 00                             o.47.

       server端结果:

source port: 49574,dest port: 8888
IP: 127.0.0.1 => 127.0.0.1
000000000000000000000000080045000025a3b14000401199147f0000017f000001c1a622b80011fe2468656c6c6f20343700
nRead is 51

        仔细对比下, 一目了然。

        注意:

        1. tcpdump多了最开始的0000,它不属于以太帧

        2. server端获取的mac为空, 难道跟环回地址有关? 有空再研究。

 

 


本文转载:CSDN博客