TCP网络通讯中connect、socket、listen、accept和setsockopt函数详解

1、TCP编程的核心步骤

2、socket函数

int socket(int domain, int type, int protocol);

 socket函数类似于open,用来打开一个网络连接,如果成功则返回一个网络文件描述符(int类型),之后我们操作这个网络连接都通过这个网络文件描述符。

参数详解:

dimain:
域,网络域,网络地址范围(IPV4或IPV6等),也就是协议簇;
AF_INET ip
AF_INET6 ipv6
AF_PACKET packet
PF_PACKET
PF_INET

type:
指定套接字类型:
SOCK_STREAM(TCP网络);
SOCK_DGRAM(UDP);
SOCK_SEQPACKET;

protocol:
指定协议,如果指定0,表示使用默认的协议;
IPPROTO_IP  IP传输协议
IPPROTO_TCP  TCP传输协议
IPPROTO_UDP  UDP协议
IPPROTO_SCTP  SCTP传输协议
IPPROTO_ICMP   ICMP协议
IPPROTO_IGMP  IGMP协议

3、connect函数

对于客户端的connect() 函数,该函数的功能为客户端主动连接服务器,建立连接是通过三次握手,而这个连接的过程是由内核完成,不是这个函数完成的,这个函数的作用仅仅是通知电脑内核,让内核自动完成TCP三次握手连接,最后把连接的结果返回给这个函数的返回值。

通常的情况,客户端的connect() 函数默认会一直阻塞,直到三次握手成功或超时失败才返回(正常的情况,这个过程很快完成)。

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

参数详解:

sockfd:
sockfd是由socket函数返回的套接字描述符。

addr:
addr是服务端地址族、服务端IP地址、服务端端口号。

addrlen:
服务端地址字节长度。

成功连接为0,失败为-1。

4、listen函数

使用主动连接套接口变为被连接套接口,使得一个进程可以接受其它进程的请求,从而成为一个服务器进程。在TCP服务器编程中listen函数把进程变为一个服务器,并指定相应的套接字变为被动连接。

listen函数在一般在调用bind之后,调用accept之前调用,它的函数原型是:

int listen(int sockfd, int backlog)
sockfd:
被listen函数作用的套接字,sockfd之前由socket函数返回。
在被socket函数返回的套接字fd之时,它是一个主动连接的套接字,
也就是此时系统假设用户会对这个套接字调用connect函数,
期待它主动与其它进程连接,然后在服务器编程中,
用户希望这个套接字可以接受外来的连接请求,也就是被动等待用户来连接。
由于系统默认时认为一个套接字是主动连接的,所以需要通过某种方式来告诉系统,
用户进程通过系统调用listen来完成这件事。

backlog:
这个参数涉及到一些网络的细节。进程处理一个一个连接请求的时候,可能还存在其它的连接请求。
因为TCP连接是一个过程,所以可能存在一种半连接的状态,有时由于同时尝试连接的用户过多,
使得服务器进程无法快速地完成连接请求。
如果这个情况出现了,服务器进程希望内核如何处理呢?
内核会在自己的进程空间里维护一个队列以跟踪这些完成的连接
但服务器进程还没有接手处理或正在进行的连接,这样的一个队列内核不可能让其任意大,
所以必须有一个大小的上限。
这个backlog告诉内核使用这个数值作为上限。
毫无疑问,服务器进程不能随便指定一个数值,内核有一个许可的范围。
这个范围是实现相关的。很难有某种统一,一般这个值会小30以内。

5、accept函数

accept()用来接受参数s的socket连接,它的函数原型是:

int accept(int s,struct sockaddr * addr,int * addrlen)

服务程序调用accept函数从处于监听状态的流套接字s的客户连接请求队列中取出排在最前的一个客户请求,并且创建一个新的套接字来与客户套接字创建连接通道,如果连接成功,就返回新创建的套接字的描述符,以后与客户套接字交换数据的是新创建的套接字;如果失败就返回 INVALID_SOCKET该函数的第一个参数指定处于监听状态的流套接字;操作系统利用第二个参数来返回新创建的套接字的地址结构;操作系统利用第三个参数来返回新创建的套接字的地址结构的长度。

简单讲就是listen()是进入监听状态,表示愿意接收连接请求。listen之后有连接请求就将其放到队列中,accept()是把新连接请求从队列中取出,建立新的socket。注意UDP的套接子不需要listen,只有TCP的套接子监听才要listen。UDP的套接子bind需要监听的端口就可以接收数据了。

6、setsockopt函数

setsockopt()函数,用于任意类型、任意状态套接口的设置选项值。尽管在不同协议层上存在选项,但本函数仅定义了最高的“套接口”层次上的选项。

int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);

 参数详解:

sockfd:
标识一个套接口的描述字。

level: 
指定控制套接字的层次.可以取四种值:
1)SOL_SOCKET: 基本套接口。
2)IPPROTO_IP: IPv4套接口。
3)IPPROTO_TCP: TCP套接口。
4) IPPROTO_IPV6:IPv6套接口

optname:
需要访问的选项名。

optval:
是一个指向变量的指针 类型:整形,套接口结构,其他结构类型:linger{},timeval{}。

optlen:
optval的大小。

成功执行时,返回0。失败返回-1,errno被设为以下的某个值 
EBADF:sock不是有效的描述词
EFAULT:optval指向的内存并非有效的进程
EINVAL:在调用setsockopt()时,optlen无效 
ENOPROTOOPT:指定的协议层不能识别选项
ENOTSOCK:sock描述的不是套接字

参考链接:https://blog.csdn.net/asklw/article/details/61427664

https://blog.csdn.net/liusandian/article/details/51785442

https://www.cnblogs.com/zhangshenghui/p/6095297.html

https://wenku.baidu.com/view/98a4cf1f376baf1ffc4fad8a.html

猜你喜欢

转载自blog.csdn.net/weixin_38621214/article/details/86565202
今日推荐