1. Include header file
#include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #include <arpa/inet.h> #include <unistd.h> #include <string.h> #include <time.h> #include <stdlib.h> #include <stdbool.h> #include <net/if.h>
2. Set src and dest, and define a global socket at the same time. We take the single column mode as the sub column
#define DEST_IP "192.168.1.53" #define DEST_PORT 996 #define SRC_IP "192.168.1.56" #define SRC_PORT 998 #define TEST_MESSAGE "This test udp message!" #define NETWORK_CAP "ens33" unsigned int m_OutSocket; struct sockaddr_in m_SocketOut;
DEST: destination IP, to which IP
SRC: native IP, that is, native IP. This determines which IP is selected to send packets and which network card is bound to this IP
3. Set initialization function
void init_udp_socket(){ }
3.1 initialize socket first
m_OutSocket = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
AF_ INET: communication protocol of IPv4
sock_raw: receive tcp udp icmp sctp protocol, and do not receive the response of data packets sent by the local machine. Secondly, do not receive packets that do not belong to the local IP
ipproto_udp:udp protocol
3.2 set the socket attribute to construct a hand for yourself and tell the socket not to construct a hand header for us
bool flag = true; setsockopt(m_OutSocket, IPPROTO_IP, IP_HDRINCL, (char*)&flag, sizeof(flag));
IPPROTO_IP:ipv4 protocol
IP_HDRINCL: the user needs to construct the protocol header. Here, the user can specify which IP to use. If this protocol is not used, the socket will automatically select an IP to use
3.3 setting send delay time
It should be noted that the send time parameter under linux is a structure
struct timeval nTimeOver={10,0}; setsockopt(m_OutSocket, SOL_SOCKET, SO_SNDTIMEO, (char*)&nTimeOver,sizeof(struct timeval));
3.4 specify dest ip and dest port of the current socket
In fact, you can not specify it, but you can't do it without specifying it, because we need to construct the hand ourselves. If you don't specify it in this step, you can't construct dest ip and prot. This is the protocol specification of socket sending packets
We used SOCK_RAW protocol, so it will not receive feedback packets. This is just to comply with the socket specification
m_SocketOut.sin_family = AF_INET; m_SocketOut.sin_addr.s_addr = inet_addr(DEST_IP); m_SocketOut.sin_port = (u_short)DEST_PORT;
3.5 binding network card
struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, NETWORK_CAP, strlen(NETWORK_CAP)); setsockopt(m_OutSocket, SOL_SOCKET, SO_BINDTODEVICE, (char *)&ifr, sizeof(ifr));
At this point, the initialization function is finished
Next, we write the send function
The sending function is complicated because we need to construct the udp hand package
4. Write sending function
Function prototype
void send(const char* buff,int length){ if( buff == NULL){ return; } }
Before we start, we define the hand package of IP and UDP:
IP:
typedef struct stuIPHEADER { unsigned char h_lenver; // 8bit 4bit version + 4bit header length (h_lenver &0xf) * 4 unsigned char tos; // 8bit service type unsigned short total_len; // Total length of 16bit (bytes) unsigned short ident; // 16bit identification unsigned short frag_and_flags; // 16bit 3bit Flag + 13bit chip offset unsigned char ttl; // 8bit lifetime (TTL) unsigned char proto; // 8bit upper layer protocol unsigned short checksum; // 16bit inspection and unsigned int sourceIP; // 32bit source IP address unsigned int destIP; // 32bit destination IP address }IPHEADER, *LPIPHEADER;
UDP:
typedef struct _UDP_HEADER { unsigned short nSourPort ; // Source port number unsigned short nDestPort ; // Destination port number unsigned short nLength ; // Packet length unsigned short nCheckSum ; // Checksum } UDP_HEADER, *PUDP_HEADER ;
Secondly, there are PSD:
typedef struct _PSD_HEADER{ unsigned long saddr; //Source IP address unsigned long daddr; //Destination IP address char mbz; //Empty (0) char ptcl; //Protocol type unsigned short plen; //Length of TCP/UDP packet (i.e. the length from the TCP/UDP header to the end of the packet, unit: bytes) } UDP_PSDHEADER,*PUDP_PSDHEADER ;
Then define a sender
#define MAX_UDP_DATA_LEN 65536 char SendBuf[MAX_UDP_DATA_LEN];
Then the construct is defined in the function body and constructed
IPHEADER ipHeader; memset(&ipHeader,0,sizeof(IPHEADER));
Construction Code:
void ConstructIPHeader(IPHEADER *pIpHeader, int dataLength) { pIpHeader->h_lenver = 0x45; //ip v4 pIpHeader->tos = 0; pIpHeader->total_len = htons(dataLength); pIpHeader->ident = htons(rand()); pIpHeader->frag_and_flags = 0; pIpHeader->ttl = 128; pIpHeader->proto = IPPROTO_UDP; pIpHeader->checksum = 0; pIpHeader->sourceIP = inet_addr(SRC_IP); pIpHeader->destIP = inet_addr(DEST_IP); }
Construct UDP package:
UDP_HEADER udpHeader; memset(&udpHeader,0,sizeof(UDP_HEADER));
Construction Code:
void ConstructUdpHeader(UDP_HEADER *pUdpHeader, int dataLength) { pUdpHeader->nSourPort = htons((unsigned short)(SRC_PORT)); pUdpHeader->nDestPort = htons((unsigned short)(DEST_PORT)); pUdpHeader->nLength = htons(sizeof(UDP_HEADER) + dataLength); pUdpHeader->nCheckSum = 0; }
Initialize the sender and include hand, buff and copy
memset(SendBuf, 0, MAX_UDP_DATA_LEN); memcpy(SendBuf, &ipHeader, sizeof(IPHEADER)); memcpy(SendBuf+sizeof(IPHEADER), &udpHeader, sizeof(UDP_HEADER)); memcpy(SendBuf+sizeof(IPHEADER)+sizeof(UDP_HEADER), buff, length);
Finally, construct the message
This message code is not my original, but is directly obtained from the udp message code constructed in the open source of socket programming.
Construction message code:
unsigned short CalculateChecksum(char *buffer1, int len1, char *buffer2, int len2) { unsigned long checksum=0; unsigned short* buffer; int i=0; buffer = (unsigned short*) buffer1; for (i=0; i<int(len1/sizeof(unsigned short)); i++) checksum += buffer[i]; buffer = (unsigned short*) buffer2; for (i=0; i<int(len2/sizeof(unsigned short)); i++) checksum += buffer[i]; if ((len2 & 0x1) != 0) checksum += (unsigned char) buffer2[len2-1]; checksum = (checksum >> 16) + (checksum & 0xffff); checksum += (checksum >>16); return (unsigned short)(~checksum); }
Then write IP message and UDP message based on message function
Construct IP message function:
void FinalIPHeader(char *pIpAndDataBuffer, int length) { IPHEADER* pIpHeader = (IPHEADER*) pIpAndDataBuffer; char* pDataBuffer = pIpAndDataBuffer + sizeof(IPHEADER); int dataLen = length - sizeof(IPHEADER); pIpHeader->checksum = CalculateChecksum(pIpAndDataBuffer, sizeof(IPHEADER), pDataBuffer, dataLen); pIpHeader->checksum = CalculateChecksum(pIpAndDataBuffer, sizeof(IPHEADER), pDataBuffer, 0); }
Function for constructing UDP message:
void CRawSocket::FinalUdpHeader(char *pUdpAndDataBuffer, int length) { UDP_PSDHEADER UDP_PSD_HEADER; memset(&UDP_PSD_HEADER,0,sizeof(UDP_PSDHEADER)); UDP_HEADER* pUdpHeader = (UDP_HEADER*) pUdpAndDataBuffer; char* pDataBuffer = pUdpAndDataBuffer + sizeof(UDP_HEADER); int dataLen = length - sizeof(UDP_HEADER); UDP_PSD_HEADER.saddr = inet_addr(SRC_IP); UDP_PSD_HEADER.daddr = inet_addr(DEST_IP); UDP_PSD_HEADER.mbz = 0; UDP_PSD_HEADER.ptcl = IPPROTO_UDP; UDP_PSD_HEADER.plen = ::htons(length); pUdpHeader->nCheckSum = CalculateChecksum((char*) &UDP_PSD_HEADER, sizeof(UDP_PSD_HEADER), pUdpAndDataBuffer, length); }
Then we construct:
FinalIPHeader(SendBuf,length+sizeof(IPHEADER)+sizeof(UDP_HEADER)); FinalUdpHeader(SendBuf+sizeof(IPHEADER),length+sizeof(UDP_HEADER));
Then we can call send_to send it to us because send_to cannot construct a hand package, so send must be used here_ to
sendto(m_OutSocket,SendBuf,length+sizeof(IPHEADER)+sizeof(UDP_HEADER), 0,(struct sockaddr*) &m_SocketOut,sizeof(struct sockaddr_in));
That's it.
Complete code + demo:
#include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #include <arpa/inet.h> #include <unistd.h> #include <string.h> #include <time.h> #include <stdlib.h> #include <stdbool.h> #include <net/if.h> #define DEST_IP "192.168.1.53" #define DEST_PORT 996 #define SRC_IP "192.168.1.56" #define SRC_PORT 998 #define TEST_MESSAGE "This test udp message!" #define NETWORK_CAP "ens33" unsigned int m_OutSocket; struct sockaddr_in m_SocketOut; typedef struct stuIPHEADER { unsigned char h_lenver; // 8bit 4bit version + 4bit header length // (h_lenver &0xf) * 4 unsigned char tos; // 8bit service type unsigned short total_len; // Total length of 16bit (bytes) unsigned short ident; // 16bit identification unsigned short frag_and_flags; // 16bit 3bit Flag + 13bit chip offset unsigned char ttl; // 8bit lifetime (TTL) unsigned char proto; // 8bit upper layer protocol unsigned short checksum; // And 16bit inspection unsigned int sourceIP; // 32bit source IP address unsigned int destIP; // 32bit destination IP address }IPHEADER, *LPIPHEADER; typedef struct _UDP_HEADER { unsigned short nSourPort ; // Source port number unsigned short nDestPort ; // Destination port number unsigned short nLength ; // Packet length unsigned short nCheckSum ; // Checksum } UDP_HEADER, *PUDP_HEADER ; typedef struct _PSD_HEADER{ unsigned long saddr; //Source IP address unsigned long daddr; //Destination IP address char mbz; //Empty (0) char ptcl; //Protocol type unsigned short plen; //Length of TCP/UDP packet (i.e. the length from the TCP/UDP header to the end of the packet, unit: bytes) } UDP_PSDHEADER,*PUDP_PSDHEADER ; #define MAX_UDP_DATA_LEN 65536 char SendBuf[MAX_UDP_DATA_LEN]; void init_udp_socket(){ m_OutSocket = socket(AF_INET, SOCK_RAW, IPPROTO_UDP); bool flag = true; setsockopt(m_OutSocket, IPPROTO_IP, IP_HDRINCL, (char*)&flag, sizeof(flag)); struct timeval nTimeOver={10,0}; setsockopt(m_OutSocket, SOL_SOCKET, SO_SNDTIMEO, (char*)&nTimeOver,sizeof(struct timeval)); struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, NETWORK_CAP, strlen(NETWORK_CAP)); setsockopt(m_OutSocket, SOL_SOCKET, SO_BINDTODEVICE, (char *)&ifr, sizeof(ifr)); m_SocketOut.sin_family = AF_INET; m_SocketOut.sin_addr.s_addr = inet_addr(DEST_IP); m_SocketOut.sin_port = (u_short)DEST_PORT; } unsigned short CalculateChecksum(char *buffer1, int len1, char *buffer2, int len2) { unsigned long checksum=0; unsigned short* buffer; int i=0; buffer = (unsigned short*) buffer1; for (i=0; i<int(len1/sizeof(unsigned short)); i++) checksum += buffer[i]; buffer = (unsigned short*) buffer2; for (i=0; i<int(len2/sizeof(unsigned short)); i++) checksum += buffer[i]; if ((len2 & 0x1) != 0) checksum += (unsigned char) buffer2[len2-1]; checksum = (checksum >> 16) + (checksum & 0xffff); checksum += (checksum >>16); return (unsigned short)(~checksum); } void FinalIPHeader(char *pIpAndDataBuffer, int length) { IPHEADER* pIpHeader = (IPHEADER*) pIpAndDataBuffer; char* pDataBuffer = pIpAndDataBuffer + sizeof(IPHEADER); int dataLen = length - sizeof(IPHEADER); pIpHeader->checksum = CalculateChecksum(pIpAndDataBuffer, sizeof(IPHEADER), pDataBuffer, dataLen); pIpHeader->checksum = CalculateChecksum(pIpAndDataBuffer, sizeof(IPHEADER), pDataBuffer, 0); } void FinalUdpHeader(char *pUdpAndDataBuffer, int length) { UDP_PSDHEADER UDP_PSD_HEADER; memset(&UDP_PSD_HEADER,0,sizeof(UDP_PSDHEADER)); UDP_HEADER* pUdpHeader = (UDP_HEADER*) pUdpAndDataBuffer; char* pDataBuffer = pUdpAndDataBuffer + sizeof(UDP_HEADER); int dataLen = length - sizeof(UDP_HEADER); UDP_PSD_HEADER.saddr = inet_addr(SRC_IP); UDP_PSD_HEADER.daddr = inet_addr(DEST_IP); UDP_PSD_HEADER.mbz = 0; UDP_PSD_HEADER.ptcl = IPPROTO_UDP; UDP_PSD_HEADER.plen = htons(length); pUdpHeader->nCheckSum = CalculateChecksum((char*) &UDP_PSD_HEADER, sizeof(UDP_PSD_HEADER), pUdpAndDataBuffer, length); } void ConstructUdpHeader(UDP_HEADER *pUdpHeader, int dataLength) { pUdpHeader->nSourPort = htons((unsigned short)(SRC_PORT)); pUdpHeader->nDestPort = htons((unsigned short)(DEST_PORT)); pUdpHeader->nLength = htons(sizeof(UDP_HEADER) + dataLength); pUdpHeader->nCheckSum = 0; } void ConstructIPHeader(IPHEADER *pIpHeader, int dataLength) { pIpHeader->h_lenver = 0x45; //ip v4 pIpHeader->tos = 0; pIpHeader->total_len = htons(dataLength); pIpHeader->ident = htons(rand()); pIpHeader->frag_and_flags = 0; pIpHeader->ttl = 128; pIpHeader->proto = IPPROTO_UDP; pIpHeader->checksum = 0; pIpHeader->sourceIP = inet_addr(SRC_IP); pIpHeader->destIP = inet_addr(DEST_IP); } void send_my(const char* buff,int length){ if( buff == NULL){ return; } IPHEADER ipHeader; memset(&ipHeader,0,sizeof(IPHEADER)); ConstructIPHeader(&ipHeader,length+sizeof(IPHEADER)+sizeof(UDP_HEADER)); UDP_HEADER udpHeader; memset(&udpHeader,0,sizeof(UDP_HEADER)); ConstructUdpHeader(&udpHeader,length); memset(SendBuf, 0, MAX_UDP_DATA_LEN); memcpy(SendBuf, &ipHeader, sizeof(IPHEADER)); memcpy(SendBuf+sizeof(IPHEADER), &udpHeader, sizeof(UDP_HEADER)); memcpy(SendBuf+sizeof(IPHEADER)+sizeof(UDP_HEADER), buff, length); FinalIPHeader(SendBuf,length+sizeof(IPHEADER)+sizeof(UDP_HEADER)); FinalUdpHeader(SendBuf+sizeof(IPHEADER),length+sizeof(UDP_HEADER)); sendto(m_OutSocket,SendBuf,(length+sizeof(IPHEADER)+sizeof(UDP_HEADER)), 0,(struct sockaddr*) &m_SocketOut,sizeof(struct sockaddr_in)); } int main(){ init_udp_socket(); while(1){ send_my(TEST_MESSAGE,strlen(TEST_MESSAGE)); usleep(200); } }
When the program is running, you can use tcpdump to grab packets, or wireshark to grab packets
Here, in order to facilitate you to watch the demonstration, I use wireshark to capture the package and demonstrate to you:
Because it is a virtual machine and has only one network card, I use one network card for demonstration:
Set Src in macro definition_ Change the IP to the corresponding IP of the network card:
#define SRC_IP "192.168.1.56"
Then test to see:
You can also see in the network card address:
Network card address in wireshark:
This indicates that we have not been optimized by the udp optimal network packet algorithm.
There will be an optimal network packet algorithm in udp. When you use udp to contract, even if you bind the IP of network card A, udp will call the algorithm in the protocol stack to determine which network card is most suitable for sending. The route is not congested. Even if the IP does not change, the network card address will change, that is, the IP of network card A you bind, However, the protocol packet contains the physical address of the B network card, which will cause the physical link layer to select the B network card to send your packet.