网络子系统78_inet套接字创建

//	inet协议族控制块
//		1.在inet_init中,由sock_register(&inet_family_ops)注册给系统
// 		2.在sys_socket系统调用中,通过协议族号查找对应的协议控制块,然后由
//		  具体协议控制块的create函数创建套接字
1.1 static const struct net_proto_family inet_family_ops = {
	.family = PF_INET,
	.create = inet_create,
	.owner	= THIS_MODULE,
};



//	为struct socket分配struct inet_sock
//	步骤:
//		0.设置struct socket->state = SS_UNCONNECTED 表示未连接状态
//		1.根据套接字类型,协议号,查找指定协议
//		2.初始化套接字操作集合(socket->ops)
//		3.分配struct sock结构,初始化sock->sk_prot指向inet_protosw->prot
//		4.初始化sock,建立struct sock与struct socket的连接
1.2 static int inet_create(struct net *net, struct socket *sock, int protocol,
		       int kern)
{
	struct sock *sk;
	struct inet_protosw *answer;
	struct inet_sock *inet;
	struct proto *answer_prot;

	int err;

	//未连接状态
	sock->state = SS_UNCONNECTED;

lookup_protocol:
	err = -ESOCKTNOSUPPORT;
	rcu_read_lock();
	//同一协议族下边具有相同套接字类型的多个不同协议
	list_for_each_entry_rcu(answer, &inetsw[sock->type], list) {

		err = 0;
		
		if (protocol == answer->protocol) {
			if (protocol != IPPROTO_IP)
				break;
		} else {
			//指定IPPROTO_IP表示匹配默认的套接字类型
			if (IPPROTO_IP == protocol) {
				protocol = answer->protocol;
				break;
			}
			//套接字类型的协议号为IPPROTO_IP,表示可以与任何协议匹配
			if (IPPROTO_IP == answer->protocol)
				break;
		}
		err = -EPROTONOSUPPORT;
	}

	//如果模块没有加载,加载协议模块
	...

	//初始化套接字操作,协议类型
	sock->ops = answer->ops; // (struct proto_ops)
	answer_prot = answer->prot; // (struct proto)
	answer_no_check = answer->no_check;
	answer_flags = answer->flags;
	rcu_read_unlock();


	err = -ENOBUFS;
	//分配sock结构
	sk = sk_alloc(net, PF_INET, GFP_KERNEL, answer_prot);
	if (sk == NULL)
		goto out;

	...

	//建立struct sock与struct socket的联系
	sock_init_data(sock, sk);

	...

out:
	return err;
out_rcu_unlock:
	rcu_read_unlock();
	goto out;
}


//	struct sock结构初始化
//		1.分配sock的队列
//		2.初始化sock各字段
//			2.1 sk->sk_state = TCP_CLOSE表示未建立连接
//		3.设置sock->sk_socket字段指向socket
1.3 void sock_init_data(struct socket *sock, struct sock *sk)
{
	//分配sock的队列
	skb_queue_head_init(&sk->sk_receive_queue);
	skb_queue_head_init(&sk->sk_write_queue);
	skb_queue_head_init(&sk->sk_error_queue);
#ifdef CONFIG_NET_DMA
	skb_queue_head_init(&sk->sk_async_wait_queue);
#endif

	sk->sk_send_head	=	NULL;

	init_timer(&sk->sk_timer);

	sk->sk_allocation	=	GFP_KERNEL;
	//接收,发送缓存的大小
	sk->sk_rcvbuf		=	sysctl_rmem_default;
	sk->sk_sndbuf		=	sysctl_wmem_default;
	//未建立连接
	sk->sk_state		=	TCP_CLOSE;
	//sk->sk_socket = socket
	sk_set_socket(sk, sock);

	sock_set_flag(sk, SOCK_ZAPPED);

	if (sock) {
		sk->sk_type	=	sock->type;
		sk->sk_wq	=	sock->wq;
		sock->sk	=	sk;
	} else
		sk->sk_wq	=	NULL;

	sk->sk_state_change	=	sock_def_wakeup;
	sk->sk_data_ready	=	sock_def_readable;
	sk->sk_write_space	=	sock_def_write_space;
	sk->sk_error_report	=	sock_def_error_report;
	sk->sk_destruct		=	sock_def_destruct;

	sk->sk_frag.page	=	NULL;
	sk->sk_frag.offset	=	0;
	sk->sk_peek_off		=	-1;

	sk->sk_peer_pid 	=	NULL;
	sk->sk_peer_cred	=	NULL;
	sk->sk_write_pending	=	0;
	sk->sk_rcvlowat		=	1;
	sk->sk_rcvtimeo		=	MAX_SCHEDULE_TIMEOUT;
	sk->sk_sndtimeo		=	MAX_SCHEDULE_TIMEOUT;

	sk->sk_stamp = ktime_set(-1L, 0);

	smp_wmb();
	atomic_set(&sk->sk_refcnt, 1);
	atomic_set(&sk->sk_drops, 0);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
#include <sys/types.h> /* See NOTES */ #include <sys/socket.h> #include <linux/socket.h> //#include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <stdlib.h> #include <unistd.h> #include <stdio.h> #include <errno.h> void handle_tcp_client(int connfd); /* struct sockaddr_in { sa_family_t sin_family; // 指定协议族 u_int16_t sin_port; //端口号 struct in_addr sin_addr; //ip地址 char sin_zero[8]; //填充8个字节,为了和其他协议族地址结构体大小一样。 }; struct in_addr { in_addr_t s_addr; }; typedef u_int32_t in_addr_t; */ int create_socket(short port, char *ipstr) { int ret; //1. 创建一个套接字 int sock = socket(AF_INET, SOCK_STREAM, 0); if (sock == -1) { perror("socket error"); return -1; } // 2. 指定本机的ip地址: ip + port struct sockaddr_in local; local.sin_family = AF_INET; //指定协议族 local.sin_port = htons(port); //指定端口号 local.sin_addr.s_addr = inet_addr(ipstr); //指定ip地址 ret = bind(sock, (struct sockaddr *)&local, sizeof(local)); if (ret == -1) { perror("bind error"); goto err_return; } //3. 进入监听模式: ret = listen(sock, 10); if (ret == -1) { perror("listen error"); goto err_return; } return sock; //返回一个创建的(已经准备好)的监听套接字 err_return: close(sock); return -1; } // tcp_server port ip_str int main(int argc, char *argv[]) { int sock; sock = create_socket( atoi(argv[1]), argv[2]); if (sock == -1) { printf("failed to create_socket\n"); return -1; } while (1) { struct sockaddr_in client; socklen_t len = sizeof(client); int connfd = accept(sock, (struct sockaddr*)&client, &len); if (connfd == -1) { perror("accept error:"); continue; } // 打印一下新连接的客户端的地址信息 //printf("%s port %d new connection established\n", // inet_ntoa(client.sin_addr), ntohs(client.sin_port) ); pid_t pid = fork(); if (pid == 0) { handle_tcp_client(connfd); exit(0); } else if (pid > 0) { close(connfd); } else { close(connfd); perror("fork error"); continue; } } }
最新发布
07-15

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值