Advanced UDP socket Programming for network programming

Source: Internet
Author: User
Tags truncated

Overview

UDP is a non-connected, unreliable datagram protocol, and any reliable transmission needs to be provided by the application, such as: time-out retransmission, serial number response mechanism, but it is efficient and convenient to use in some situations. It supports broadcast and multicast. The basic UDP socket programming reference to this article, this is only on that basis, to record some of the problems in the UDP programming easy to appear.

Secondary data

Auxiliary data (also known as control information) can be used by calling the Recvmsg and sendmsg functions, where the definitions of the two functions refer to the article "Advanced I/O", using the Msg_control and Msg_controllen members in the MSGHDR structure to send and receive auxiliary data.

The following are the various uses of ancillary data:


The secondary data consists of one or more secondary data objects, each of which begins with a struct CMSGHDR. The structure is defined as follows:

   /* struct cmsghdr*/   struct CMSGHDR {       socklen_t cmsg_len;    /* Data byte count, including header */       int       cmsg_level;  /* Originating protocol */       int       cmsg_type;   /* protocol-specific Type */       * followed by unsigned char cmsg_data[]; */   };

While Msg_control points to the first secondary data object, the total length of the secondary data is msg_controllen specified. At the beginning of each object is a CMSGHDR structure that describes the object. There can be padding bytes between the Cmsg_type member and the actual data, and there can be padding bytes from the end of the data to the next secondary data object. As shown in the following:



The following are macro definitions for working with secondary data:

 #include <sys/socket.h>/* macro definition */struct CMSGHDR *cmsg_firsthdr (struct MSGHDR *msgh);   struct CMSGHDR *cmsg_nxthdr (struct msghdr *msgh, struct CMSGHDR *cmsg);   size_t cmsg_align (size_t length);   size_t cmsg_space (size_t length);   size_t Cmsg_len (size_t length);   unsigned char *cmsg_data (struct CMSGHDR *cmsg);    /* struct cmsghdr*/struct CMSGHDR {socklen_t cmsg_len;  /* Data byte count, including header */int cmsg_level;   /* Originating protocol */INT cmsg_type; /* protocol-specific type */* followed by unsigned char cmsg_data[]; */};/* These macros define control information (also known as auxiliary data) that is used to create and access a portion of the socket payload; * These control information may contain the interface of the received datagram and a variety of rarely used descriptive first-class information; */CMSG_FIRSTHDR (); /* Returns a pointer to the first CMSGHDR structure of the secondary data buffer, returns NULL if no secondary data is returned, */CMSG_NXTHDR (),/* Returns a pointer to the next CMSGHDR structure, and returns null;*/cmsg_align if no more helpers are available  ();/* Given a length, returns it including the required align‐ment. This is a constant expression. */Cmsg_space ()/* Returns the size of a secondary data object for a given amount of data */Cmsg_data ();/* Returns a pointer to the CMSGHDR nodeA pointer to the first byte of the associated data, */Cmsg_len ();/* Returns the value of the given amount of data stored in the Cmsg_len; */ 


The difference between Cmsg_len and Cmsg_space is that the former does not count the possible padding bytes after the data portion of the secondary data object, and therefore returns the value that is used to hold the Cmsg_len member, which is the possible padding byte at the end of the This returns the size of the dynamically allocated space for the secondary data object. The above macro definitions are used in the following ways:

    struct MSGHDR msg;    struct CMSGHDR *cmptr;    for (cmptr = CMSG_FIRSTHDR (&msg); Cmptr! = NULL; cmptr = Cmsg_nxthdr (&msg, cmptr))    {        if (cmptr->cmsg_ Level = = ... &&                cmptr->cmsg_type = = ...)        {            U_char *ptr;            ptr = Cmsg_data (cmptr);            /* Process data pointer to by PTR */        }    }

Receive flag, destination IP address, and interface index

The following uses auxiliary data to implement a function similar to the RECVFROM function, which returns three values: Returns the MSG_FLAGS receive flag, the destination IP address of the receiving datagram, and the interface index of the receiving datagram. Where the header file Un.h just defines the IP address and interface index for the return structure purpose.

#ifndef un_h#define un_h#include <netinet/in.h>/* custom struct, member contains destination address, interface index */struct unp_in_pktinfo{    struct in_ Addr  ipi_addr;   /* Destination IPV4 address */    int             ipi_ifindex;/* received interface index */}; #endif


/* Function: similar to recvfrom function; * Return value: * 1, return msg_flags value, * 2, return the destination address of the received datagram (obtained by IP_RECVDSTADDR socket option); * 3. Returns the index of the received datagram Interface (by IP_ RECVIF socket option); */#include <sys/socket.h> #include <unistd.h> #include <netinet/in.h> #include < string.h> #include "un.h" ssize_t recvfrom_flag (int fd, void *ptr, size_t nbytes, int *flags, struct sockaddr * SA , socklen_t *salenptr, struct unp_in_pktinfo *pktp) {struct MSGHDR msg;/* need to call recvmsg function, so the struct must be defined */struct IOVEC IO v[1];/* non-contiguous buffers, where only one buffer is defined */ssize_t n; #ifdef Have_msghdr_msg_control/* If the Msg_control member is supported initialize the following value auxiliary data */struct    CMSGHDR *cmptr;        union{struct CMSGHDR cm;    Char control[cmsg_space (sizeof (struct in_addr)) + cmsg_space (sizeof (struct unp_in_pktinfo))];    } Control_un;    Msg.msg_control = Control_un.control;    Msg.msg_controllen = sizeof (Control_un.control); msg.msg_flags = 0; #else/* If Msg_control control information is not supported, it is directly initialized to 0 */bzero (&msg, sizeof (msg)), #endif/* Assignment initializes the MSGHDR structure * /msg. msg_name = sa;    Msg.msg_namelen = *salenptr;    Iov[0].iov_base = ptr;    Iov[0].iov_len = nbytes;    Msg.msg_iov = Iov;    Msg.msg_iovlen = 1;  if (n = recvmsg (fd, &msg, *flags)) < 0) return (n);/* ERROR return */* If the RECVMSG call returns successfully, execute the following program */*salenptr = msg.msg_namelen;/* value-The result parameter must return */if (PKTP)/* Initialize the UNP_IN_PKTINFO structure, with the address 0.0.0.0, the index of the set interface is 0 */bzero (PKTP, size of (struct unp_in_pktinfo));/* 0.0.0.0, i/f = 0 */#ifndef have_msghdr_msg_control/* If Msg_control control information is not supported, set the pending return flag to 0 and return    */*flags = 0;/* value-the result parameter returns */return (n); /* The following programs are part of the process that supports Msg_control control information */#else/* Returns flag information */*flags = msg.msg_flags;/* value-the result parameter returns */if (Msg.msg_controllen            < sizeof (struct CMSGHDR) | | (Msg.msg_flags & Msg_ctrunc) | |    PKTP = = NULL) return (n); /* Processing Auxiliary data */for (cmptr = CMSG_FIRSTHDR (&msg); Cmptr! = NULL; cmptr = Cmsg_nxthdr (&msg, cmptr)) {#ifdef ip_re CVDSTADDR/* Handles IP_RECVDSTADDR, returns the destination address of the receiving datagram */* where ipproto_ip means IPV4 domain */if (Cmptr->cmsg_level = = Ipproto_ip && Cmptr->cmsg_type = = ip_recvdstaddr)            {memcpy (&pktp->ipi_addr, Cmsg_data (cmptr), sizeof (struct in_addr));        Continue                } #endif #ifdef ip_recvif/* Handles IP_RECVIF, returns the interface index of the receiving datagram */if (Cmptr->cmsg_level = = Ipproto_ip &&            Cmptr->cmsg_type = = ip_recvif) {struct SOCKADDR_DL *sdl;/* data link address structure contains interface index members */            SDL = (struct SOCKADDR_DL *) cmsg_data (CMPTR);            Pktp->ipi_ifindex = sdl->sdl_index;        Continue    } #endif Err_quit ("Unknown ancillary data"); } return (n); #endif}
Here we use this function to implement the previously documented "basic UDP Socket Programming" program, where the server's handler becomes the following implementation:

#include <sys/socket.h> #include <string.h> #include <stdio.h> #include <netinet/in.h># Include "Un.h" #include <net/if.h> #include the size of the <arpa/inet.h>/* limit datagram is 20 bytes */#undefMAXLINE #definemaxline20 /* To see datagram truncation */extern ssize_t recvfrom_flag (int, void *, size_t, int *, struct sockaddr*, socklen_t *, S Truct unp_in_pktinfo *); extern char * sock_ntop (const struct sockaddr *, socklen_t); Voiddg_echo (int sockfd, struct SOCKAD Dr *pcliaddr, socklen_t Clilen) {intflags;const Inton = 1;socklen_tlen;ssize_tn;charmesg[maxline], str[INET6_ Addrstrlen],ifname[ifnamsiz];struct in_addrin_zero;struct unp_in_pktinfopktinfo;/* If ip_recvdsatddr and IP_ are supported Recvif socket options, set them */#ifdefIP_RECVDSTADDRif (setsockopt (SOCKFD, Ipproto_ip, ip_recvdstaddr, &on, sizeof (ON)) < 0 ) Err_ret ("SetSockOpt of Ip_recvdstaddr"); #endif #ifdefip_recvifif (setsockopt, SOCKFD, Ipproto_ip, Ip_recvif, sizeof (ON)) < 0) Err_ret ("SetSockOpt of Ip_recvif"); #endifbzero (&in_zero, sizeof (struct in_addr));/* All 0 IPv4 address */for (;;)        {len = clilen;flags = 0;        /* Read datagrams from sockets */n = Recvfrom_flag (SOCKFD, MESG, MAXLINE, &flags, Pcliaddr, &len, &pktinfo);  /* Displays the number of bytes read, the maximum number of bytes can not exceed 20 bytes, if exceeded, the truncation occurs; * Call Sock_ntop to convert the source IP address and port number to the expression format and output */printf ("%d-byte datagram from%s", N,        Sock_ntop (PCLIADDR, Len)); /* If the IP address returned is not 0, call the inet_ntop conversion destination IP address format and output */if (memcmp (&pktinfo.ipi_addr, &in_zero, sizeof (In_zero))! = 0)        printf (", to%s", Inet_ntop (Af_inet, &AMP;PKTINFO.IPI_ADDR,STR, sizeof (str)));        printf (", index =%d", pktinfo.ipi_ifindex); /* If the returned interface index is not 0, call If_indextoname to get the interface name and display */if (Pktinfo.ipi_ifindex > 0) printf (", recv i/f =%s", If_indextoname (Pkti        Nfo.ipi_ifindex, ifname));        printf (", flags =%d", flags); /* The following is a test of 4 flags */#ifdefMSG_TRUNCif (Flags & Msg_trunc) printf ("(Datagram truncated)"); #endif #ifdefmsg_ctruncif ( Flags & Msg_ctrunc) printf ("Control info truncated"); #endif #ifdefmsg_bcastif(Flags & Msg_bcast) printf ("(broadcast)"); #endif #ifdefmsg_mcastif (Flags & msg_mcast) printf ("(multicast)");        endifprintf ("\ n"); /* echo text string to client */sendto (SOCKFD, MESG, N, 0, pcliaddr, len);}}

Using the UDP protocol

features of the UDP protocol : Support for broadcast and multicast, no need to establish connection and removal;

Characteristics of TCP Protocol : Acknowledgement response, time-out retransmission, repeating packet detection, sorting disorder grouping, windowed flow control, slow start and congestion avoidance;

Therefore, the UDP protocol must be used in the following situations: broadcast or multicast; simple request-reply application; Note: UDP protocol should be avoided for mass data transfer.

Because UDP is an unreliable transport protocol, the application must provide: Timeout retransmission, serial number confirmation response mechanism;

Concurrent UDP Servers

For a TCP concurrent server, you only need to fork to create a new child process, but for UDP you must deal with two different types of servers:

    1. UDP Simple Server : When a customer request is read and a confirmation answer is sent, it is no longer relevant to the customer. In this case, the server that reads the client request can fork to create a new child process and let the child process process the request.
    2. UDP Complex Server : The UDP server exchanges multiple datagrams with the customer. The problem is that the client knows that the server port number is only a well-known port on the server. A customer sends its request to the first datagram to reach this port, but how the server distinguishes this is a subsequent datagram from the customer's same request is a request datagram from another customer, and the workaround is to have the server create a new socket for each customer on which bind binds a temporary port. The socket is then used to send all replies to the customer.


Resources:

"Unix Network Programming"

Network programming advanced UDP Sockets programming

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.