这是socket.c中的sys_sendto()函数代码.
/** Send a datagram to a given address. We move the address into kernel(将一个数据包送到给定的地址)
* space and check the user space data area is readable before invoking(我们移动这个地址到内核空间)
* the protocol.(并在调用协议前检查用户空间的数据与是否可读.)
*/
asmlinkage long sys_sendto(int fd, void * buff, size_t len, unsigned flags,
struct sockaddr *addr, int addr_len)
/*无连接模式的套接字一经建立(并且绑定到一个套接字地址)以后就可以
*进行通信,而无需先建立连接.此时,每个报文都要提供对方的地址.
*所以,sento()用于程序界面为:int sendto(int s, const void *msg, size_t len, int flags, const struct sockaddr *to, socklen_t tolen);
*参数to 指向对方的地址即:sockaddr数据结构.而tolen则为地址的长度.这个函数是专为
*"无连接"模式设计的.若工作在"有连接"模式则应将参数to 设置成NULL,而将tolen设置成0.*/
{
struct socket *sock; //套接字结构体
char address; //地址
int err;
struct msghdr msg; //报文结构体.每个msghdr数据结构代表着一个报文.
struct iovec iov; //一块数据.
//struct数据结构声明:(在include\linux\uio.h中)
//struct iovec
//{
// void *iov_base; /* BSD uses caddr_t (1003.1g requires void *) */
// __kernel_size_t iov_len; /* Must be size_t (1003.1g) */
//};
sock = sockfd_lookup(fd, &err); //根据文件描述符得到相应的套接字.
if (!sock) //如果失败则跳转到相应的处理程序段.
goto out;
iov.iov_base=buff; //将要传递的报文信息附给iov数据块.该数
iov.iov_len=len; //据块成为要发送的报文的代表.
msg.msg_name=NULL; //为报文附值.(名字暂时为空,得到地址后再为它附值)
msg.msg_iov=&iov; //数据块被封装到报文中.
msg.msg_iovlen=1; //报文的数据块长度为1.
msg.msg_control=NULL; //控制字段为空,只是发送而已没有其他控制信息.
msg.msg_controllen=0;
msg.msg_namelen=0;
if(addr)
{
err = move_addr_to_kernel(addr, addr_len, address); //将地址移到内核空间.
if (err < 0) //如果失败则跳到相关的处理段.
goto out_put;
msg.msg_name=address; //成功则为名字字段附值.
msg.msg_namelen=addr_len;
}
if (sock->file->f_flags & O_NONBLOCK) //对于标志位flag的处理?????????????????
flags |= MSG_DONTWAIT;
msg.msg_flags = flags;
err = sock_sendmsg(sock, &msg, len); //通过套接字发送报文.
out_put: //将地址移到内核空间失败,先将sock输出再返回错误码.
sockfd_put(sock);
out: //根据文件描述符得到相应的套接字失败,直接返回错误码.
return err;
}
标着一串问号的地方,是我不明白的地方,这个flag究竟起着怎样的作用,它和那些与他做运算的常数之间是什么关系?
多谢!! 判断socket是否阻塞 多谢:) 为什么要将地址addr移入系统空间而不直接使用addr
系统应该可以直接使用用户态的地址啊 而且两者的虚拟地址是一样的
页:
[1]