现在的位置: 首页 > 综合 > 正文

发送udp数据包

2017年12月22日 ⁄ 综合 ⁄ 共 2552字 ⁄ 字号 评论关闭

  在Socket编程中,发送数据报文可供使用的API函数有send,sendto和sendmsg,下面是关于前两个系统调用的原型:
#include <sys/socket.h>
ssize_t send( int socket, const void *buffer, size_t length, int flags );
     请注意它的返回值的类型ssize_t,其含义是signed size。从内核代码中,我们可以看到,在32位系统上,它是int,在64位系统上,它是long。它常用于表示在某一次操作后,缓冲区中可以被读或写的字节数量。相对应的,还有一个数据类型size_t,其含义是unsigned size。常用于表示对象本身的大小,操作sizeof的返回值就是该类型,malloc,memcpy等函数的参数中用该类型表示对象的大小,在32位系统上,它是unsigned int,在64位系统上,它是unsigned long。
     send执行成功,会返回被发送出去的数据报文的字节数,如果执行失败,则会返回-1(所以不能返回size_t类型),并且可以从errno上查找到错误原因。
#include <sys/socket.h>
ssize_t sendto(int socket, const void *message, size_t length,
                 int flags, const struct sockaddr *dest_addr,
                  socklen_t dest_len);
在内核的实现中,send和sendto系统调用最终都会调用到内核函数:
asmlinkage long sys_sendto(int fd, void __user * buff, size_t len, unsigned flags,
       struct sockaddr __user *addr, int addr_len)
     在send系统调用中,参数addr被置为NULL,addr_len为0。sys_sendto首先根据传入的描述符fd,找到对应的struct socket结构体。然后构建内核的消息结构struct msghdr:
struct msghdr {
   void * msg_name;
   int   msg_namelen;
   struct iovec * msg_iov;
   __kernel_size_t msg_iovlen;
   void   * msg_control;
   __kernel_size_t msg_controllen;
   unsigned msg_flags;
};
     msg_name和msg_namelen就是数据报文要发向的对端的地址信息(即sendto系统调用中的addr和addr_len)。当使用send时,它们的值为NULL和0。msg_iov的定义如下:
struct iovec
{
   void __user *iov_base;
   __kernel_size_t iov_len;
};
表示存放待发送数据的一个缓冲区,iov_base是缓冲区的起始地址,指向message, iov_len是缓冲区的长度,指向length。msg_iovlen是缓冲区的数量,对于sendto和send来讲,msg_iovlen都是1。msg_flags即为传入的参数flags,现在暂时不过多的关注flags的应用。msg_control和msg_controllen暂时不关注。
     sys_sendto构建完这些后,调用sock_sendmsg继续执行发送流程,传入参数为struct msghdr和数据的长度。忽略中间的一些不重要的细节,sock_sendmsg继续调用__sock_sendmsg,__sock_sendmsg最后调用struct socket->ops->sendmsg,即对应套接字类型的sendmsg函数,所有的套接字类型的sendmsg函数都是inet_sendmsg,该函数首先检查本地端口是否已绑定,无绑定则执行自动绑定,而后调用具体协议的sendmsg函数。
     下面再来看sendmsg系统调用:
#include <sys/socket.h>
ssize_t sendmsg(int socket, const struct msghdr *message, int flags);
     可以看到,它跟send和sendto的最大区别就是struc msghdr由用户来构建完成,对应的内核处理函数是sys_sendmsg。

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/arau_sh/archive/2008/09/26/2981678.aspx

 

 

对上面的补充说明:

在sendmsg中,首先创建一个udp socket,没有指定该msg传到什么地方.

而是在msghdr结果体中,进行设置,如:

        cmd.type = type;
        cmd.length = datalen;

        iov[0].iov_base = (void *)&cmd;
        iov[0].iov_len = UPNP_WPS_CMD_SIZE;
        iov[1].iov_base = (void *)databuf;
        iov[1].iov_len = datalen;

        to.sin_family = AF_INET;
        to.sin_port = htons(UPNP_WPS_PORT + context->focus_ifp->if_instance);
        to.sin_addr.s_addr = inet_addr(UPNP_WPS_ADDR);

        memset(&msg, 0, sizeof(msg));
        msg.msg_name = (void *)&to;
        msg.msg_namelen = sizeof(to);
        msg.msg_iov = iov;
        msg.msg_iovlen = 2;

        sendmsg(wfactrl->m_write, &msg, 0);

 

抱歉!评论已关闭.