资讯

展开

SylixOS-UDP网络应用编程

作者:快盘下载 人气:

        在使用UDP编写应用程序时与TCP编写应用程序有着本质的差异;其原因在于这两个传输层之间的差异;UDP是无连接不可靠的数据报协议;不同于TCP提供的面向连接的可靠字节流。然而有些场合更适合使用UDP;使用UDP编写的一些流行的应用程序有DNS;域名系统;、NFS;网络文件系统;、SNMP;简单网络管理协议;。

        客户端无需与服务器端建立连接;但是需要指定目的地址;服务器地址;;并且客户端只管给服务器发送数据报。

        服务器端不接受来自客户端的连接;而是只管等待来自某个客户端的数据。

如图 3.3所示给出了典型的UDP客户端与服务器端程序的函数使

SylixOS-UDP网络应用编程

         bind函数把一个本地协议地址赋予一个套接字;协议地址的含义只取决于协议本身。对于网际协议;协议地址是32位的IPv4地址或128位IPv6地址与16位的TCP或UDP端口的组合。调用bind函数可以指定IP地址或端口;可以两者都指定;也可以都不指定。

#include <sys/socket.h>
int  bind(int s, const struct sockaddr *name, socklen_t namelen);
函数bind原型分析;
	此函数成功返回0;失败返回-1并设置错误号;
	参数s是套接字;socket函数返回;;
	参数name是一个指向特定协议域的sockaddr结构体类型的指针;
	参数namelen 表示name结构的长度。

        如图 所示给出了典型的UDP客户端与服务器端程序中recvfrom与sendto使用过程;类似于标准的read与write函数;不过需要额外三个参数;。

#include <sys/socket.h>
ssize_t  recvfrom(int  s, void	*mem, size_t  len, int  flags,
                     struct sockaddr *from, socklen_t *fromlen);
函数recvfrom原型分析;
	此函数成功时返回读取到数据的字节数;失败时返回-1并设置错误号;
	参数s是套接字;socket函数返回;;
	参数mem是指向读入缓冲区的指针;
	参数len表示读取数据的字节长度;
	参数flags用于指定消息类型;当不关心此参数时可以将其设置为0;如果需要关心此参数请将其值配置为以下值;
	MSG_PEEK;数据预读但不删除数据;
	MSG_WAITALL;等待所有数据到达后才返回;
	MSG_OOB;带外数据;
	MSG_DONTWAIT;不阻塞的接收数据;
	MSG_MORE;有更多的数据需要发送。
	参数from用于表示UDP数据报发送者的协议地址;例如IP地址及端口号;;
	参数fromlen用于指定from地址大小的指针。

        由于UDP是无连接的;因此recvfrom函数返回值为0也是有可能的。如果from参数是一个空指针;那么相应的长度参数fromlen也必须是一个空指针;表示我们并不关心数据发送者的协议地址。

#include <sys/socket.h>
ssize_t  sendto(int  s, const void *data, size_t  size, int  flags,
                   const struct sockaddr *to, socklen_t  tolen);
函数sendto原型分析;
	此函数成功时返回读取到数据的字节数;失败时返回-1并设置错误号;
	参数s是套接字;socket函数返回;;
	参数data是指向写入数据缓冲区的指针;
	参数size表示写入数据的字节长度;
	参数flags用于指定消息类型;当不关心此参数时可以将其设置为0;如果需要关心此参数请将其值配置为以下值;
	MSG_PEEK;数据预读但不删除数据;
	MSG_WAITALL;等待所有数据到达后才返回;
	MSG_OOB;带外数据;
	MSG_DONTWAIT	;不阻塞的接收数据;
	MSG_MORE;有更多的数据需要发送。
	参数to用于表示UDP数据报接收者的协议地址;例如IP地址及端口号;;
	参数tolen用于指定to地址长度。

         sendto函数写一个长度为0的数据报是可行的;这导致一个只包含IP头部;对于IPv4通常为20个字节;对于IPv6通常为40个字节;和一个8字节UDP头部但没有数据的IP数据报。

        UDP回射程序模型;如下图所示。客户端与服务器遵循该流程完成回射数据的接收与回显。

        客户端程序使用sendto函数将“SylixOS Hello;”发送给服务器;并使用recvfrom读回服务器的回射;最后将收到的回射信息“SylixOS Hello;”输出。

        服务器程序使用recvfrom函数读入来自客户端的“SylixOS Hello;”数据;并通过sendto把收到的数据发送给客户端程序。

                                                       UDP回射服务器程序

#include <stdio.h>
#include <string.h>
#include <sys/socket.h>

#define __UDP_ECHO_TYPE_CLIENT         	1  		/* 客户端模式                	*/
#define __UDP_ECHO_TYPE_SERVER        	2 		/* 服务器模式                	*/
												/* 当前模式选择              	*/
#define __UDP_ECHO_TYPE                	(__UDP_ECHO_TYPE_SERVER)
              									/* 客户端 IP 地址            	*/
#define __UDP_ECHO_IP_CLIENT           	;192.168.1.16;
              									/* 服务器 IP 地址            	*/
#define __UDP_ECHO_IP_SERVER          	;192.168.1.17;
#define __UDP_ECHO_PORT_CLIENT        	8000 	/* 客户端端口号                	*/
#define __UDP_ECHO_PORT_SERVER         	8001	/* 服务器端口号               	*/
#define __UDP_ECHO_BUFF_SIZE_CLIENT	257		/* 客户端接收缓冲区大小      	*/
#define __UDP_ECHO_BUFF_SIZE_SERVER   	257		/* 服务器接收缓冲区大小        	*/
static int  __UdpEchoServer (void)
{
    int                  	iRet      = -1;			/* 操作结果                    	*/
    int                	sockFd    = -1;     		/* socket 描述符          	  	*/
										/* 地址结构大小            	  	*/
socklen_t			uiAddrLen = sizeof(struct sockaddr_in);     
register ssize_t		sstRecv   = 0;      		/* 接收到的数据长度        	  	*/
												/* 接收缓冲区                  	*/
char                	cRecvBuff[__UDP_ECHO_BUFF_SIZE_SERVER] ={0};    
struct sockaddr_in 	sockaddrinLocal; 		/* 本地地址               	  	*/ 
struct sockaddr_in	sockaddrinRemote;   	/* 远端地址                   	*/

    fprintf(stdout, ;UDP echo server start.
;);
												/* 创建 socket           	  	*/
sockFd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 
if (sockFd < 0) {							/* 操作失败                   	*/
        printf(;UDP echo server socket error.
;);
        return  (-1);    							/* 错误返回                  	*/
    }
    /*
     * 初始化本地地址结构
     */
    												/* 清空地址信息              	*/
    memset(&sockaddrinLocal, 0, sizeof(sockaddrinLocal));
    												/* 地址结构大小              	*/
    sockaddrinLocal.sin_len         	= sizeof(struct sockaddr_in);
sockaddrinLocal.sin_family     	= AF_INET;	/* 地址族                     	*/
												/* 网络地址                  	*/
sockaddrinLocal.sin_addr.s_addr	= INADDR_ANY;           
												/* 绑定服务器端口             	*/
    sockaddrinLocal.sin_port        	= htons(__UDP_ECHO_PORT_SERVER);
iRet = bind(sockFd,
                 (struct sockaddr *)&sockaddrinLocal,
			    sizeof(sockaddrinLocal)); 		/* 绑定本地地址与端口         	*/
    if (iRet < 0) {                    			/* 绑定操作失败               	*/
        close(sockFd);    						/* 关闭已经创建的 socket    	*/
        fprintf(stderr, ;UDP echo server bind error.
;);
        return  (-1);                        		/* 错误返回                  	*/
    }
    for (;;) {
        											/* 清空接收缓冲区             	*/
memset(&cRecvBuff[0], 0, __UDP_ECHO_BUFF_SIZE_SERVER);                   
sstRecv = recvfrom(sockFd,
                               (void *)&cRecvBuff[0],
                               __UDP_ECHO_BUFF_SIZE_SERVER,
                               0,
                               (struct sockaddr *)&sockaddrinRemote,
                               &uiAddrLen);   		/* 从远端接收数据             	*/
        if (sstRecv <= 0) {                    		/* 接收数据失败                	*/
            if ((errno != ETIMEDOUT  ) &&
                (errno != EWOULDBLOCK)) {      	/* 非超时与非阻塞              	*/
                 close(sockFd);               		/* 关闭已经创建的 socket     	*/
                 fprintf(stderr, ;UDP echo server recvfrom error.
;);
                 return  (-1);
            }
            continue;
        }
        sendto(sockFd,
                 (const void *)&cRecvBuff[0],
                 sstRecv,
                 0,
                 (const struct sockaddr *)&sockaddrinRemote,
                 uiAddrLen);
    }
    return  (0);
}

                                                UDP回射客户端程序

#include <stdio.h>
#include <string.h>
#include <sys/socket.h>

#define __UDP_ECHO_TYPE_CLIENT        	1  		/* 客户端模式                 	*/
#define __UDP_ECHO_TYPE_SERVER       	2 		/* 服务器模式                 	*/
												/* 当前模式选择              	*/
#define __UDP_ECHO_TYPE                	(__UDP_ECHO_TYPE_CLIENT)
              									/* 客户端 IP 地址           	*/
#define __UDP_ECHO_IP_CLIENT         	;192.168.1.16;
              									/* 服务器 IP 地址            	*/
#define __UDP_ECHO_IP_SERVER           	;192.168.1.17;
#define __UDP_ECHO_PORT_CLIENT     		8000 	/* 客户端端口号              	*/
#define __UDP_ECHO_PORT_SERVER        	8001	/* 服务器端口号             	*/

#define __UDP_ECHO_BUFF_SIZE_CLIENT   	257		/* 客户端接收缓冲区大小      	*/
#define __UDP_ECHO_BUFF_SIZE_SERVER	257		/* 服务器接收缓冲区大小      	*/

static int  __UdpEchoClient (void)
{
    int                	 sockFd      = -1;     	/* socket 描述符         	  	*/
        											/* 地址结构大小               	*/
    socklen_t           	 uiAddrLen	= sizeof(struct sockaddr_in);
    register ssize_t   	 sstRecv     = 0;    		/* 接收到的数据长度           	*/
    register ssize_t  	 sstSend     = 0;  		/* 接收到的数据长度         	*/
    												/* 需要发送的字符串          	*/
    const char          	*pcSendData = ;SylixOS Hello!
;; 
    												/* 接收缓冲区                 	*/
    char                 	 cRecvBuff[__UDP_ECHO_BUFF_SIZE_CLIENT] ={0};
    struct sockaddr_in	 sockaddrinRemote;		/* 远端地址                  	*/
    
    fprintf(stdout, ;UDP echo client start.
;);
                      								/* 创建 socket            	  	*/
    sockFd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (sockFd < 0) {
        fprintf(stderr, ;UDP echo client socket error.
;);
        return  (-1);
    }
    /*
     * 初始化远端地址结构
     */
    memset(&sockaddrinRemote, 0, sizeof(sockaddrinRemote));
     											/* 地址转换错误               	*/
    if (!inet_aton(__UDP_ECHO_IP_SERVER, &sockaddrinRemote.sin_addr)) {
        close(sockFd);              				/* 关闭已经创建的 socket      	*/
        fprintf(stderr, ;UDP echo client get addr error.
;);
        return  (-1);                   			/* 错误返回                   	*/
    }
          										/* 地址结构大小               	*/
    sockaddrinRemote.sin_len   	= sizeof(struct sockaddr_in);
    sockaddrinRemote.sin_family	= AF_INET;		/* 地址族                     	*/
       											/* 绑定服务器端口             	*/
    sockaddrinRemote.sin_port	= htons(__UDP_ECHO_PORT_SERVER);
    for (;;) {
        fprintf(stdout, ;Send Data: %s;, pcSendData);
        sstRecv = strlen(pcSendData);			/* 获取发送字符串长度         	*/
        sstSend = sendto(sockFd,
                            (const void *)pcSendData,
                             sstRecv,
                             0,
                            (const struct sockaddr *)&sockaddrinRemote,
                             uiAddrLen); 			/* 发送数据到指定的服务器端    	*/
        if (sstSend <= 0) { 						/* 发送数据失败               	*/
            if ((errno != ETIMEDOUT  ) &&
                (errno != EWOULDBLOCK)) {			/* 非超时与非阻塞              	*/
                 close(sockFd);                  	/* 关闭已经创建的 socket	  	*/
                
                 fprintf(stderr, ;UDP echo client sendto error.
;);
                 return  (-1);    					/* 错误返回                   	*/
            }
            continue;        						/* 超时或非阻塞后重新运行      	*/
        }
        memset(&cRecvBuff[0], 0, __UDP_ECHO_BUFF_SIZE_CLIENT);
        sstRecv = recvfrom(sockFd,
                               (void *)&cRecvBuff[0],
                               __UDP_ECHO_BUFF_SIZE_SERVER,
                               0,
                              (struct sockaddr *)&sockaddrinRemote,
                               &uiAddrLen);		    	/* 从远端接收数据             	*/
        if (sstRecv <= 0) {     					/* 接收数据失败                	*/
            if ((errno != ETIMEDOUT  ) &&
                (errno != EWOULDBLOCK)) {   		/* 非超时与非阻塞               */
                 close(sockFd);      				/* 关闭已经创建的 socket       */
                 fprintf(stderr, ;UDP echo client recvfrom error.
;);
                 return  (-1);      				/* 错误返回                     */
            }
            continue;                     			/* 超时或非阻塞后重新运行        */
        }
        fprintf(stdout, ;Recv Data: ;);
        cRecvBuff[sstRecv] = 0;
        fprintf(stdout, %s
;, &cRecvBuff[0]);
        sleep(5);                     				/* 休眠一段时间                  */
    }
    return  (0);
}

 

加载全部内容

相关教程
猜你喜欢
用户评论
快盘暂不提供评论功能!