网络函数listen源码分析

static int sock_listen(int fd, int backlog)
{
	struct socket *sock;

	if (fd < 0 || fd >= NR_OPEN || current->files->fd[fd] == NULL)
		return(-EBADF);
	if (!(sock = sockfd_lookup(fd, NULL))) 
		return(-ENOTSOCK);

	if (sock->state != SS_UNCONNECTED) 
	{
		return(-EINVAL);
	}

	if (sock->ops && sock->ops->listen)
		sock->ops->listen(sock, backlog);
	// 设置socket的监听属性,accept函数时用到
	sock->flags |= SO_ACCEPTCON;
	return(0);
}
static int inet_listen(struct socket *sock, int backlog)
{
	struct sock *sk = (struct sock *) sock->data;
	// 如果没有绑定端口则绑定一个,并把sock加到sock_array中
	if(inet_autobind(sk)!=0)
		return -EAGAIN;

	/* We might as well re use these. */ 
	/*
	 * note that the backlog is "unsigned char", so truncate it
	 * somewhere. We might as well truncate it to what everybody
	 * else does..
	 */
	if ((unsigned) backlog > 128)
		backlog = 128;
	// 设置syn+已连接队列的最大长度,在tcp.c中用到
	sk->max_ack_backlog = backlog;
	// 防止多次调用listen
	if (sk->state != TCP_LISTEN)
	{	
		// syn+已连接队列长度
		sk->ack_backlog = 0;
		sk->state = TCP_LISTEN;
	}
	return(0);
}
// 绑定一个随机的端口,更新sk的源端口字段,并把sk挂载到端口对应的队列中
static int inet_autobind(struct sock *sk)
{
	// 已经绑定了端口则直接返回,否则获取一个随机的端口
	if (sk->num == 0) 
	{
		sk->num = get_new_socknum(sk->prot, 0);
		if (sk->num == 0) 
			return(-EAGAIN);
		put_sock(sk->num, sk);
		sk->dummy_th.source = ntohs(sk->num);
	}
	return 0;
}

listen函数主要的工作包括,设置socket和sock结构体的标记和状态,设置syn和已连接队列的上限。

好的,关于lwIP(V1.0.0) RAW API函数源码分析系列的第四篇,我们来看一下tcp_accept()函数。 在lwIP中,tcp_accept()函数的作用是接受一个连接请求并创建新的TCP连接。下面是tcp_accept()函数的代码实现: ```c struct tcp_pcb * tcp_accept(struct tcp_pcb *pcb, err_t *err) { struct tcp_pcb_listen *lpcb = (struct tcp_pcb_listen*)pcb; struct tcp_pcb *npcb; LWIP_ASSERT("tcp_accept: invalid pcb", lpcb != NULL); LWIP_ASSERT("tcp_accept: invalid pcb state", lpcb->state == LISTEN); /* Check if there is a connection request */ if (lpcb->accept == NULL) { *err = ERR_VAL; return NULL; } /* Set pcb->accept to NULL before calling tcp_listen() again as accept is only valid for one iteration! */ npcb = lpcb->accept; lpcb->accept = NULL; /* Call the accept callback function */ if (lpcb->accept_cb) { struct tcp_pcb *ret; ret = lpcb->accept_cb(lpcb->callback_arg, npcb, ERR_OK); if (ret) { npcb = ret; } } /* Set state of the new PCB */ npcb->state = SYN_RCVD; npcb->rcv_nxt = npcb->rcv_isn = lpcb->rcv_nxt; npcb->snd_wl1 = lpcb->snd_wl1; npcb->snd_wl2 = lpcb->snd_wl2; npcb->callback_arg = lpcb->callback_arg; /* Insert the new PCB into the list of active PCBs */ pcb_active_insert(npcb); /* We now need to call tcp_listen() to make the PCB active */ tcp_listen(npcb); return npcb; } ``` tcp_accept()函数的参数pcb是一个监听pcb,它的类型是tcp_pcb_listen。而返回值则是一个新的已连接pcb,它的类型是tcp_pcb。 在函数开头,首先进行了一些参数的检查,如果出现异常,就会返回NULL并设置错误号err。 接下来,tcp_accept()会检查是否有连接请求。如果没有,也会返回NULL并设置错误号err。 如果有连接请求,tcp_accept()会将pcb->accept设置为NULL,并将连接请求保存到npcb中。然后,它会调用回调函数lpcb->accept_cb,如果有需要的话。如果回调函数返回了一个新的pcb,tcp_accept()会将npcb设置为新的pcb。 在接下来的操作中,tcp_accept()会设置npcb的状态为SYN_RCVD,并将一些信息从监听pcb复制到npcb中。最后,tcp_accept()会将npcb插入到活动pcb列表中,并调用tcp_listen()函数使npcb变为活动状态。 这就是tcp_accept()函数的主要实现过程。它的作用是非常重要的,因为它允许我们接受新的TCP连接请求并创建新的TCP连接。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值