A socket is a communications end-point that is bound to a UDP or TCP port within the node. Under VxWorks, your application can use the sockets interface to access features of the Internet Protocol suite (features such as multicasting). Depending on the bound port type, a socket is referred to either as a stream socket or a datagram socket. VxWorks sockets are UNIX BSD 4.4 compatible. However, VxWorks does not support signal functionality for sockets.
Stream sockets use TCP to bind to a particular port number. Another process, on any host in the network, can then create another stream socket and request that it be connected to the first socket by specifying its host Internet address and port number. After the two TCP sockets are connected, there is a virtual circuit set up between them, allowing reliable socket-to-socket communications. This style of communication is conversational.
Datagram sockets use UDP to bind to a particular port number. Other processes, on any host in the network, can then send messages to that socket by specifying the host Internet address and the port number. Compared to TCP, UDP provides a simpler but less robust communication method. In a UDP communication, data is sent between sockets in separate, unconnected, individually addressed packets called datagrams. There is no sense of conversation with a datagram socket. The communication is in the style of a letter. Each packet carries the address of both the destination and the sender. Compared to TCP, UDP is unreliable. Like the mail, packets that are lost or out-of-sequence are not reported.
There are a number of complex network programming issues that are beyond the scope of this guide. For additional information, consult a socket-programming book, such as one of the following:
The Transmission Control Protocol (TCP) provides reliable, two-way transmission of data. In a TCP communication, two sockets are connected, allowing a reliable byte-stream to flow between them in either direction. TCP is referred to as a virtual circuit protocol, because it behaves as though a circuit is created between the two sockets.
A good analogy for TCP communications is a telephone system. Connecting two sockets is similar to calling from one phone to another. After the connection is established, you can write and read data (talk and listen).
Table 7-1 shows the steps in establishing socket communications with TCP, and the analogy of each step with telephone communications.
|
|||||||||||||||||||
|
|||||||||||||||||||
|
|||||||||||||||||||
The following code example uses a client-server communication model. The server communicates with clients using stream-oriented (TCP) sockets. The main server loop, in tcpServerWorkTask( ), reads requests, prints the client's message to the console, and, if requested, sends a reply back to the client. The client builds the request by prompting for input. It sends a message to the server and, optionally, waits for a reply to be sent back. To simplify the example, we assume that the code is executed on machines that have the same data sizes and alignment.
/* tcpExample.h - header used by both TCP server and client examples */ /* defines */ #define SERVER_PORT_NUM 5001 /* server's port number for bind() */ #define SERVER_WORK_PRIORITY 100 /* priority of server's work task */ #define SERVER_STACK_SIZE 10000 /* stack size of server's work task */ #define SERVER_MAX_CONNECTIONS 4 /* max clients connected at a time */ #define REQUEST_MSG_SIZE 1024 /* max size of request message */ #define REPLY_MSG_SIZE 500 /* max size of reply message */ /* structure for requests from clients to server */ struct request { int reply; /* TRUE = request reply from server */ int msgLen; /* length of message text */ char message[REQUEST_MSG_SIZE]; /* message buffer */ };
/* tcpClient.c - TCP client example */ /* DESCRIPTION This file contains the client-side of the VxWorks TCP example code. The example code demonstrates the usage of several BSD 4.4-style socket routine calls. */ /* includes */ #include "vxWorks.h" #include "sockLib.h" #include "inetLib.h" #include "stdioLib.h" #include "strLib.h" #include "hostLib.h" #include "ioLib.h" #include "tcpExample.h" /**************************************************************************** * * tcpClient - send requests to server over a TCP socket * * This routine connects over a TCP socket to a server, and sends a * user-provided message to the server. Optionally, this routine * waits for the server's reply message. * * This routine may be invoked as follows: * -> tcpClient "remoteSystem" * Message to send: * Hello out there * Would you like a reply (Y or N): * y * value = 0 = 0x0 * -> MESSAGE FROM SERVER: * Server received your message * * RETURNS: OK, or ERROR if the message could not be sent to the server. */ STATUS tcpClient ( char * serverName /* name or IP address of server */ ) { struct request myRequest; /* request to send to server */ struct sockaddr_in serverAddr; /* server's socket address */ char replyBuf[REPLY_MSG_SIZE]; /* buffer for reply */ char reply; /* if TRUE, expect reply back */ int sockAddrSize; /* size of socket address structure */ int sFd; /* socket file descriptor */ int mlen; /* length of message */ /* create client's socket */ if ((sFd = socket (AF_INET, SOCK_STREAM, 0)) == ERROR) { perror ("socket"); return (ERROR); } /* bind not required - port number is dynamic */ /* build server socket address */ sockAddrSize = sizeof (struct sockaddr_in); bzero ((char *) &serverAddr, sockAddrSize); serverAddr.sin_family = AF_INET; serverAddr.sa_len = (u_char) sockAddrSize; serverAddr.sin_port = htons (SERVER_PORT_NUM); if (((serverAddr.sin_addr.s_addr = inet_addr (serverName)) == ERROR) && ((serverAddr.sin_addr.s_addr = hostGetByName (serverName)) == ERROR)) { perror ("unknown server name"); close (sFd); return (ERROR); } /* connect to server */ if (connect (sFd, (struct sockaddr *) &serverAddr, sockAddrSize) == ERROR) { perror ("connect"); close (sFd); return (ERROR); } /* build request, prompting user for message */ printf ("Message to send: \n"); mlen = read (STD_IN, myRequest.message, REQUEST_MSG_SIZE); myRequest.msgLen = mlen; myRequest.message[mlen - 1] = '\0'; printf ("Would you like a reply (Y or N): \n"); read (STD_IN, &reply, 1); switch (reply) { case 'y': case 'Y': myRequest.reply = TRUE; break; default: myRequest.reply = FALSE; break; } /* send request to server */ if (write (sFd, (char *) &myRequest, sizeof (myRequest)) == ERROR) { perror ("write"); close (sFd); return (ERROR); } if (myRequest.reply) /* if expecting reply, read and display it */ { if (read (sFd, replyBuf, REPLY_MSG_SIZE) < 0) { perror ("read"); close (sFd); return (ERROR); }
/* tcpServer.c - TCP server example */
The following code example uses a client-server communication model. The server communicates with clients using datagram-oriented (UDP) sockets. The main server loop, in udpServer( ), reads requests and optionally displays the client's message. The client builds the request by prompting the user for input. Note that this code assumes that it executes on machines that have the same data sizes and alignment.
/* udpExample.h - header used by both UDP server and client examples */ #define SERVER_PORT_NUM 5002 /* server's port number for bind() */ #define REQUEST_MSG_SIZE 1024 /* max size of request message */ /* structure used for client's request */ struct request { int display; /* TRUE = display message */ char message[REQUEST_MSG_SIZE]; /* message buffer */ };
/* udpClient.c - UDP client example */ /* DESCRIPTION This file contains the client-side of the VxWorks UDP example code. The example code demonstrates the useage of several BSD 4.4-style socket routine calls. */ /* includes */ #include "vxWorks.h" #include "sockLib.h" #include "inetLib.h" #include "stdioLib.h" #include "strLib.h" #include "hostLib.h" #include "ioLib.h" #include "udpExample.h" /**************************************************************************** * * udpClient - send a message to a server over a UDP socket * * This routine sends a user-provided message to a server over a UDP socket. * Optionally, this routine can request that the server display the message. * This routine may be invoked as follows: * -> udpClient "remoteSystem" * Message to send: * Greetings from UDP client * Would you like server to display your message (Y or N): * y * value = 0 = 0x0 * * RETURNS: OK, or ERROR if the message could not be sent to the server. */ STATUS udpClient ( char * serverName /* name or IP address of server */ ) { struct request myRequest; /* request to send to server */ struct sockaddr_in serverAddr; /* server's socket address */ char display; /* if TRUE, server prints message */ int sockAddrSize; /* size of socket address structure */ int sFd; /* socket file descriptor */ int mlen; /* length of message */ /* create client's socket */ if ((sFd = socket (AF_INET, SOCK_DGRAM, 0)) == ERROR) { perror ("socket"); return (ERROR); } /* bind not required - port number is dynamic */ /* build server socket address */ sockAddrSize = sizeof (struct sockaddr_in); bzero ((char *) &serverAddr, sockAddrSize); serverAddr.sa_len = (u_char) sockAddrSize; serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons (SERVER_PORT_NUM); if (((serverAddr.sin_addr.s_addr = inet_addr (serverName)) == ERROR) && ((serverAddr.sin_addr.s_addr = hostGetByName (serverName)) == ERROR)) { perror ("unknown server name"); close (sFd); return (ERROR); } /* build request, prompting user for message */ printf ("Message to send: \n"); mlen = read (STD_IN, myRequest.message, REQUEST_MSG_SIZE); myRequest.message[mlen - 1] = '\0'; printf ("Would you like the server to display your message (Y or N): \n"); read (STD_IN, &display, 1); switch (display) { case 'y': case 'Y': myRequest.display = TRUE; break; default: myRey = FALSE; break; } /* send request to server */ if (sendto (sFd, (caddr_t) &myRequest, sizeof (myRequest), 0, (struct sockaddr *) &serverAddr, sockAddrSize) == ERROR) { perror ("sendto"); close (sFd); return (ERROR); } close (sFd); return (OK); }
/* udpServer.c - UDP server example */ /* DESCRIPTION This file contains the server-side of the VxWorks UDP example code. The example code demonstrates the useage of several BSD 4.4-style socket routine calls. */ /* includes */ #include "vxWorks.h" #include "sockLib.h" #include "inetLib.h" #include "stdioLib.h" #include "strLib.h" #include "ioLib.h" #include "fioLib.h" #include "udpExample.h" /********************************************************************* * * udpServer - read from UDP socket and display client's message if requested * * Example of VxWorks UDP server: * -> sp udpServer * task spawned: id = 0x3a1f6c, name = t2 * value = 3809132 = 0x3a1f6c * -> MESSAGE FROM CLIENT (Internet Address 150.12.0.11, port 1028): * Greetings from UDP client * * RETURNS: Never, or ERROR if a resources could not be allocated. */ STATUS udpServer (void) { struct sockaddr_in serverAddr; /* server's socket address */ struct sockaddr_in clientAddr; /* client's socket address */ struct request clientRequest; /* request/Message from client */ int sockAddrSize; /* size of socket address structure */ int sFd; /* socket file descriptor */ char inetAddr[INET_ADDR_LEN]; /* buffer for client's inet addr */ /* set up the local address */ sockAddrSize = sizeof (struct sockaddr_in); bzero ((char *) &serverAddr, sockAddrSize); serverAddr.sa_len = (u_char) sockAddrSize; serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons (SERVER_PORT_NUM); serverAddr.sin_addr.s_addr = htonl (INADDR_ANY); /* create a UDP-based socket */ if ((sFd = socket (AF_INET, SOCK_DGRAM, 0)) == ERROR) { perror ("socket"); return (ERROR); } /* bind socket to local address */ if (bind (sFd, (struct sockaddr *) &serverAddr, sockAddrSize) == ERROR) { perror ("bind"); close (sFd); return (ERROR); } /* read data from a socket and satisfy requests */ FOREVER { if (recvfrom (sFd, (char *) &clientRequest, sizeof (clientRequest), 0, (struct sockaddr *) &clientAddr, &sockAddrSize) == ERROR) { perror ("recvfrom"); close (sFd); return (ERROR); } /* if client requested that message be displayed, print it */ if (clientRequest.display) { /* convert inet address to dot notation */ inet_ntoa_b (clientAddr.sin_addr, inetAddr); printf ("MSG FROM CLIENT (Internet Address %s, port %d):\n%s\n", inetAddr, ntohs (clientAddr.sin_port), clientRequest.message); } } }
Multicasting is the delivery of the same packets to multiple IP addresses. Typical multicasting applications include audio and video conferencing, resource discovery tools, and shared white boards. Multicasting is a feature of the IP layer, but to access this function, an application uses a UDP socket.
A VxWorks process must multicast on a network interface driver that supports multicasting (many do not). To review the capabilities of all attached network drivers, use ifShow( ). If a network interface supports multicasting, IFF_MULTICAST is listed among the flags for that network interface.
Multicast IP addresses range from 224.0.0.0 to 239.255.255.255. These addresses are also called class D addresses or multicast groups. A datagram with a class D destination address is delivered to every process that has joined the corresponding multicast group.
To multicast a packet, a VxWorks process need do nothing special. The process just sends to the appropriate multicast address. The process can use any normal UDP socket. To set the route to the destination multicast address, use routeAdd( ).
To receive a multicast packet, a VxWorks process must join a multicast group. To do this, the VxWorks process must set the appropriate socket options on the socket (see Table 7-2).
|
|||||||||||||||||||
|
|||||||||||||||||||
|
|||||||||||||||||||
1: For more on multicasting socket options, see the setsockopt( ) reference entry. |
When choosing an address upon which to multicast, remember that certain addresses and address ranges are already registered to specific uses and protocols. For example, 244.0.0.1 multicasts to all systems on the local subnet. The Internet Assigned Numbers Authority (IANA) maintains a list of registered IP multicast groups. The current list can be found in RFC 1700. For more information about the IANA, see RFC 1700. Table 7-3 lists some of the well-known multicast groups.
|
|||||||||||||||||||
|
|||||||||||||||||||
|
|||||||||||||||||||
The following code samples define two routines, mcastSend( ) and mcastRcv( ). These routines demonstrate how to use UDP sockets to handle sending and receiving multicast traffic.
mcastSend( ) transmits a buffer to the specified multicast address. As input, this routine expects a multicast destination, a port number, a buffer pointer, and a buffer length. For example:
status = mcastSend ("224.1.0.1", 7777, bufPtr, 100);
mcastRcv( )receives any packet sent to a specified multicast address. As input, this routine expects the interface address from which the packet is coming, a multicast address, a port number, and the number of bytes to read from the packet. The returned value of the function is a pointer a buffer containing the read bytes. For example:
buf = mcastRcv (ifAddress, "224.1.0.1", 7777, 100) ;
/* includes */ #include "vxWorks.h" #include "taskLib.h" #include "socket.h" #include "netinet/in.h" #include "stdio.h" #include "stdlib.h" #include "string.h" #include "sockLib.h" #include "inetLib.h" #include "ioLib.h" #include "routeLib.h" /* defines */ /* globals */ /* forward declarations */ STATUS mcastSend (char * mcastAddr, USHORT mcastPort, char * sendBuf, int sendLen); char * mcastRcv (char * ifAddr, char * mcastAddr, USHORT mcastPort, int numRead); /************************************************************************ * mcastSend - send a message to the multicast address * This function sends a message to the multicast address * The multicast group address to send, the port number, the pointer to the * send buffer and the send buffer length are given as input parameters. * RETURNS: OK if sucessful or ERROR */ STATUS mcastSend ( char * mcastAddr, /* multicast address */ USHORT mcastPort, /* udp port number */ char * sendBuf, /* send Buffer */ int sendLen /* length of send buffer */ ) { struct sockaddr_in sin; struct sockaddr_in toAddr; int toAddrLen; int sockDesc; char * bufPtr; int len; /* create a send and recv socket */ if ((sockDesc = socket (AF_INET, SOCK_DGRAM, 0)) < 0 ) { printf (" cannot open send socket\n"); return (ERROR); } /* zero out the structures */ bzero ((char *)&sin, sizeof (sin)); bzero ((char *)&toAddr, sizeof (toAddr)); sin.sa_len = (u_char) sizeof(sin); sin.sin_family = AF_INET; sin.sin_addr.s_addr = INADDR_ANY; sin.sin_port = htons(0); if (bind(sockDesc, (struct sockaddr *)&sin, sizeof(sin)) != 0) { perror("bind"); if (sockDesc) close (sockDesc); return (ERROR); } toAddrLen = sizeof(struct sockaddr_in); toAddr.sa_len = (u_char) toAddrLen; toAddr.sin_family = AF_INET; /* initialize the address to the send */ toAddr.sin_addr.s_addr = inet_addr (mcastAddr); /* initialize the port to send */ toAddr.sin_port = htons(mcastPort); bufPtr = sendBuf; /* initialize the buffer pointer */ /* send the buffer */ while (sendLen > 0) { if ((len = sendto (sockDesc, bufPtr, sendLen, 0, (struct sockaddr *)&toAddr, toAddrLen)) < 0 ) { printf("mcastSend sendto errno:0x%x\n", errno ); break; } sendLen -= len; bufPtr += len; taskDelay (1); /* give a taskDelay */ } if (sockDesc != ERROR) close (sockDesc); return (OK); } /************************************************************************ * mcastRcv - receive a message from a multicast address * This function receives a message from a multicast address * The interface address from which to receive the multicast packet, * the multicast address to recv from, the port number and the number of * bytes to read are given as input parameters to this routine. * RETURNS: Pointer to the Buffer or NULL if error. */ char * mcastRcv ( char * ifAddr, /* interface address to recv mcast packets */ char * mcastAddr, /* multicast address */ USHORT mcastPort, /* udp port number to recv */ int numRead /* number of bytes to read */ ) { struct sockaddr_in fromAddr; struct sockaddr_in sin; int fromLen; struct ip_mreq ipMreq; int recvLen; int sockDesc; char * bufPtr; int status = OK; char * recvBuf = NULL; if ((sockDesc = socket (AF_INET, SOCK_DGRAM, 0)) < 0) { printf (" cannot open recv socket\n"); return (NULL); } bzero ((char *)&sin, sizeof (sin)); bzero ((char *) &fromAddr, sizeof(fromAddr)); fromLen = sizeof(fromAddr); if ((recvBuf = calloc (numRead, sizeof (char))) == NULL) { printf (" calloc error, cannot allocate memory\n"); status = ERROR; goto cleanUp; } sin.sa_len = (u_char) sizeof(sin); sin.sin_family = AF_INET; sin.sin_addr.s_addr = INADDR_ANY; /* UDP port number to match for the received packets */ sin.sin_port = htons (mcastPort); /* bind a port number to the socket */ if (bind(sockDesc, (struct sockaddr *)&sin, sizeof(sin)) != 0) { perror("bind"); status = ERROR; goto cleanUp; } /* fill in the argument structure to join the multicast group */ /* initialize the multicast address to join */ ipMreq.imr_multiaddr.s_addr = inet_addr (mcastAddr); /* unicast interface addr from which to receive the multicast packets */ ipMreq.imr_interface.s_addr = inet_addr (ifAddr); /* set the socket option to join the MULTICAST group */ if (setsockopt (sockDesc, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&ipMreq, sizeof (ipMreq)) < 0) { printf ("setsockopt IP_ADD_MEMBERSHIP error:\n"); status = ERROR; goto cleanUp; } /* get the data destined to the above multicast group */ bufPtr = recvBuf; while (numRead > 0) { if ((recvLen = recvfrom (sockDesc, bufPtr, numRead, 0, (struct sockaddr *)&fromAddr, &fromLen)) < 0) { perror("recvfrom"); status = ERROR; break; } numRead -= recvLen; /* decrement number of bytes to read */ bufPtr += recvLen; /* increment the buffer pointer */ } /* set the socket option to leave the MULTICAST group */ if (setsockopt (sockDesc, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char *)&ipMreq, sizeof (ipMreq)) < 0) printf ("setsockopt IP_DROP_MEMBERSHIP error:\n"); cleanUp: { if (sockDesc != ERROR) close (sockDesc); if ((status != OK) && (recvBuf != NULL)) { free (recvBuf); recvBuf = NULL; } } return (recvBuf); }