分析linux中套接字的实现-------创建

套接字是一种使用系统的文件描述符和系统进程进行通信的一种方法。

1、下面是描述套接字地址的结构体:

struct sockaddr {

sa_family_t sa_family; /* address family, AF_xxx */

如果使用了tcp/ip协议,AF_INET

char sa_data[14]; /* 14 bytes of protocol address */

};

2、socket的系统调用:

我们创建套接字都是用socket来创建。

socket的系统调用:

//每一个网络操作函数都有一个对应 的宏定义代码

#define SYS_SOCKET 1 /* sys_socket(2) */

#define SYS_BIND 2 /* sys_bind(2) */

#define SYS_CONNECT 3 /* sys_connect(2) */

#define SYS_LISTEN 4 /* sys_listen(2) */

#define SYS_ACCEPT 5 /* sys_accept(2) */

#define SYS_GETSOCKNAME 6 /* sys_getsockname(2) */

#define SYS_GETPEERNAME 7 /* sys_getpeername(2) */

#define SYS_SOCKETPAIR 8 /* sys_socketpair(2) */

#define SYS_SEND 9 /* sys_send(2) */

#define SYS_RECV 10 /* sys_recv(2) */

#define SYS_SENDTO 11 /* sys_sendto(2) */

#define SYS_RECVFROM 12 /* sys_recvfrom(2) */

#define SYS_SHUTDOWN 13 /* sys_shutdown(2) */

#define SYS_SETSOCKOPT 14 /* sys_setsockopt(2) */

#define SYS_GETSOCKOPT 15 /* sys_getsockopt(2) */

#define SYS_SENDMSG 16 /* sys_sendmsg(2) */

#define SYS_RECVMSG 17 /* sys_recvmsg(2) */

在linux中,所有网络函数都通过sys_socketcall来实现:

asmlinkage long sys_socketcall(int call, unsigned long __user *args)

{

unsigned long a[6];

unsigned long a0, a1;

int err;

//入参的范围判断

if (call < 1 || call > SYS_RECVMSG)

return -EINVAL;

/* copy_from_user should be SMP safe. */

if (copy_from_user(a, args, nargs[call]))//将用户态的数组拷贝给A

return -EFAULT;

err = audit_socketcall(nargs[call] / sizeof(unsigned long), a);//record audit data for sys_socketcall

if (err)

return err;

a0 = a[0];

a1 = a[1];

switch (call) {

case SYS_SOCKET:

err = sys_socket(a0, a1, a[2]);

break;

case SYS_BIND:

err = sys_bind(a0, (struct sockaddr __user *)a1, a[2]);

break;

case SYS_CONNECT:

err = sys_connect(a0, (struct sockaddr __user *)a1, a[2]);

break;

case SYS_LISTEN:

err = sys_listen(a0, a1);

break;

case SYS_ACCEPT:

err =

sys_accept(a0, (struct sockaddr __user *)a1,

(int __user *)a[2]);

break;

case SYS_GETSOCKNAME:

err =

sys_getsockname(a0, (struct sockaddr __user *)a1,

(int __user *)a[2]);

break;

case SYS_GETPEERNAME:

err =

sys_getpeername(a0, (struct sockaddr __user *)a1,

(int __user *)a[2]);

break;

case SYS_SOCKETPAIR:

err = sys_socketpair(a0, a1, a[2], (int __user *)a[3]);

break;

case SYS_SEND:

err = sys_send(a0, (void __user *)a1, a[2], a[3]);

break;

case SYS_SENDTO:

err = sys_sendto(a0, (void __user *)a1, a[2], a[3],

(struct sockaddr __user *)a[4], a[5]);

break;

case SYS_RECV:

err = sys_recv(a0, (void __user *)a1, a[2], a[3]);

break;

case SYS_RECVFROM:

err = sys_recvfrom(a0, (void __user *)a1, a[2], a[3],

(struct sockaddr __user *)a[4],

(int __user *)a[5]);

break;

case SYS_SHUTDOWN:

err = sys_shutdown(a0, a1);

break;

case SYS_SETSOCKOPT:

err = sys_setsockopt(a0, a1, a[2], (char __user *)a[3], a[4]);

break;

case SYS_GETSOCKOPT:

err =

sys_getsockopt(a0, a1, a[2], (char __user *)a[3],

(int __user *)a[4]);

break;

case SYS_SENDMSG:

err = sys_sendmsg(a0, (struct msghdr __user *)a1, a[2]);

break;

case SYS_RECVMSG:

err = sys_recvmsg(a0, (struct msghdr __user *)a1, a[2]);

break;

default:

err = -EINVAL;

break;

}

return err;

}

linux应用层的程序通过标准的BSDsocket接口实现网络通信。在BSD中,用socket描述一个套接字,主要使用在BSD套接口层。

/**

*  struct socket - general BSD socket

*  @state: socket state (%SS_CONNECTED, etc)

*  @flags: socket flags (%SOCK_ASYNC_NOSPACE, etc)

*  @ops: protocol specific socket operations

*  @fasync_list: Asynchronous wake up list

*  @file: File back pointer for gc

*  @sk: internal networking protocol agnostic socket representation

*  @wait: wait queue for several uses

*  @type: socket type (%SOCK_STREAM, etc)

*/

struct socket {

socket_state state;

unsigned long flags;

const struct proto_ops *ops;//socket函数操作表

struct fasync_struct *fasync_list;

struct file *file;

struct sock *sk;

wait_queue_head_t wait;

short type;//数据报的类型

};

struct sock *sk;指向套接口对应INET套接字结构体struct sock,

根据协议去创建相关的套接字

struct net_proto_family {

int family;

int (*create)(struct net *net, struct socket *sock, int protocol);//协议族的创建函数

struct module *owner;

};

如:IPV4

static struct net_proto_family inet_family_ops = {

.family = PF_INET,

.create = inet_create,

.owner = THIS_MODULE,

};

3.套接字的创建:

asmlinkage long sys_socket(int family, int type, int protocol)

{

int retval;

struct socket *sock;

//创建套接字

retval = sock_create(family, type, protocol, &sock);

if (retval < 0)

goto out;

retval = sock_map_fd(sock);//关联文件系统

if (retval < 0)

goto out_release;

out:

/* It may be already another descriptor 8) Not kernel problem. */

return retval;

out_release:

sock_release(sock);

return retval;

}

int sock_create(int family, int type, int protocol, struct socket **res)

{

return __sock_create(current->nsproxy->net_ns, family, type, protocol, res, 0);

}

//socket的创建函数

static int __sock_create(struct net *net, int family, int type, int protocol,

struct socket **res, int kern)

{

int err;

struct socket *sock;

const struct net_proto_family *pf;

/*

*      Check protocol is in range

*/

if (family < 0 || family >= NPROTO)

return -EAFNOSUPPORT;

if (type < 0 || type >= SOCK_MAX)

return -EINVAL;

/* Compatibility.

This uglymoron is moved from INET layer to here to avoid

deadlock in module load.

*/

if (family == PF_INET && type == SOCK_PACKET) {

static int warned;

if (!warned) {

warned = 1;

printk(KERN_INFO "%s uses obsolete (PF_INET,SOCK_PACKET)\n",

current->comm);

}

family = PF_PACKET;//AF_INET

}

//追踪这个函数将会发现

err = security_socket_create(family, type, protocol, kern);

if (err)

return err;

/*

* Allocate the socket and allow the family to set things up. if

* the protocol is 0, the family is instructed to select an appropriate

* default.

*/

sock = sock_alloc();//分配socket结构体空间

if (!sock) {

if (net_ratelimit())

printk(KERN_WARNING "socket: no more sockets\n");

return -ENFILE; /* Not exactly a match, but its the

closest posix thing */

}

sock->type = type;

#if defined(CONFIG_KMOD)

/* Attempt to load a protocol module if the find failed.

*

* 12/09/1996 Marcin: But! this makes REALLY only sense, if the user

* requested real, full-featured networking support upon configuration.

* Otherwise module support will break!

*/

if (net_families[family] == NULL)

request_module("net-pf-%d", family);

#endif

rcu_read_lock();

pf = rcu_dereference(net_families[family]);

err = -EAFNOSUPPORT;

if (!pf)

goto out_release;

/*

* We will call the ->create function, that possibly is in a loadable

* module, so we have to bump that loadable module refcnt first.

*/

if (!try_module_get(pf->owner))

goto out_release;

/* Now protected by module ref count */

rcu_read_unlock();

err = pf->create(net, sock, protocol);

if (err < 0)

goto out_module_put;

/*

* Now to bump the refcnt of the [loadable] module that owns this

* socket at sock_release time we decrement its refcnt.

*/

if (!try_module_get(sock->ops->owner))

goto out_module_busy;

/*

* Now that we‘re done with the ->create function, the [loadable]

* module can have its refcnt decremented

*/

module_put(pf->owner);

err = security_socket_post_create(sock, family, type, protocol, kern);

if (err)

goto out_sock_release;

*res = sock;

return 0;

out_module_busy:

err = -EAFNOSUPPORT;

out_module_put:

sock->ops = NULL;

module_put(pf->owner);

out_sock_release:

sock_release(sock);

return err;

out_release:

rcu_read_unlock();

goto out_sock_release;

}

时间: 2024-10-14 17:49:42

分析linux中套接字的实现-------创建的相关文章

Linux 原始套接字--myping的实现

一.套接字的类型 A.流套接字(SOCK_STREAM) 用于提供面向连接.可靠的数据传输服务,其使用传输层的TCP协议 B.数据报套接字(SOCK_DGRAM) 用于提供一个无连接.不可靠的服务,其使用传输层上的UDP协议 C.原始套接字(SOCK_RAM) 原始套接字是相对表中套接字(即前面两种套接字)而言的.它与标准套接字的区别是原始套接字可以读写内核没有处理的IP数据包,流套接字只能读取TCP协议的数据,数据报套接字只能读取UDP协议的数据. 所以要访问其他协议的数据必须使用原始套接字.

linux netlink套接字实现类似ss命令 ,统计套接字以及TCP信息

参考了 ss的源代码 以及 netlink相关资料:http://blog.csdn.net/scdxmoe/article/details/27711205 实现结果为: gcc netlink_dig_530_7.c -o netlink_dig_530_7 ./netlink_dig_530_7 state      family     l.addr     l.port       r.addr     r.rport LISTEN     AF_INET   localhost  

Linux编程---套接字

网络相关的东西几乎都是建立在套接字之上.所以这个内容对于程序员来说还是蛮重要的啊. 其实套接字也就是一个特殊的设备文件而已,我始终不能明白为什么要叫套接字.这么个奇怪的名字.不过还是就这样算了吧.关键还是编程上.由于其重要性,我还是写的详细一点吧. 一.套接字 核心函数: int  socket(int domain,int type,int protocol); 这个函数在通信域domain中创建一个类型为type,使用协议protocol的套接字.并且返回一个描述字,也就是相当于打开了一个特

nginx源码分析--监听套接字的创建 套接字的监听 HTTP请求创建连接

作为一个web服务器,那么肯定是有监听套接字的,这个监听套接字是用于接收HTTP请求的,这个监听套接字的创建是根据配置文件的内容来创建的,在nginx.conf文件中有多少个地址就需要创建多少个监听套接字.这里不说各个结构体的构造 只说大体情况! 1).首先在main函数中调用了ngx_init_cycle()函数,在这个函数的最后调用了ngx_open_listening_sockets函数,这个函数负责将创建的监听套接字进行套接字选项的设置(比如非阻塞.接受发送的缓冲区.绑定.监听处理) 2

Linux/UNIX套接字连接

套接字连接 套接字是一种通信机子.凭借这样的机制.客户/server系统的开发工作既能够在本地单机上进行.也能够夸网络进行. 套接字的创建和使用与管道是有差别的.由于套接字明白地将客户和server区分开来. 套接字连接: 首先,server应用程序用系统调用socket来创建一个套接字,它是系统分配给该server进程的类似文件描写叙述符的资源,它不能与其它进程共享. 接下来.server进程会给套接字起个名字.本地套接字的名字是Linux文件系统中的文件名称,对于网络套接字它的名字是与客户连

linux 的套接字

套接字是一种通信机制,凭借这种机制,客户/服务器系统的开发工作既可以在本地单机上进行,也可以跨网络进行. 套接字的特性有三个属性确定,它们是:域(domain),类型(type),和协议(protocol).套接字还用地址作为它的名字.地址的格式随域(又被称为协议族,protocol family)的不同而不同.每个协议族又可以使用一个或多个地址族定义地址格式. 1.套接字的域 域指定套接字通信中使用的网络介质.最常见的套接字域是AF_INET,它是指Internet网络,许多Linux局域网使

linux netlink套接字学习资料

理论: http://blog.csdn.net/unbutun/article/details/3394061 进一步深入: http://edsionte.com/techblog/archives/4134 http://edsionte.com/techblog/archives/4140 http://edsionte.com/techblog/archives/4134 实践: http://bbs.chinaunix.net/thread-3766684-1-1.html 附录代码

包分析(原始套接字七)

紧接上节,DecodeIpPack()函数完成包的解析: //IP包解析int DecodeIpPack(char *buf, int iBufSize){ IP_HEADER *pIpheader; int iProtocol, iTTL; char szProtocol[MAX_PROTO_TEXT_LEN]; char szSourceIP[MAX_ADDR_LEN], szDestIP[MAX_ADDR_LEN]; SOCKADDR_IN saSource, saDest; pIphea

Linux中如何查看文件的最初创建时间

查看 一个文件的 最初创建时间: Linux中如何查看文件的最初创建时间 linux 目前Linux没有直接查看创建文件的命令,你只能通过文件是否被修改过来进行判断. //查看代码stat 文件名 //例如:[[email protected] ~]# stat 1.txt  File: "1.txt"  Size: 18              Blocks: 8          IO Block: 4096   普通文件Device: fd00h/64768d    Inode