Linux网络编程-网络io与select,poll,epoll

问题

1、select、poll、epoll分别是什么?

2、有什么区别?

1.主机之间的通信离不开网络,沟通方式可以用TCP、UDP,广播等

TCP,socket连接:

首先了解下socket是怎么使用的

socket主要有以下函数:socket,listen,connect,bind,accept,send,sendto,recv,recvfrom,close,shutdown

网络中的进程都是由socket进行通信的,在linux和windows环境下的头文件主要是:

#include <sys/socket.h>和#include <winSock2.h>

下面介绍每个函数的具体使用方法和功能。

1.socket

int socket(int domain, int type, int protocol),这个函数建立一个协议族为domain、协议类型为type、协议编号为protocol的套接字文件描述符。如果函数调用成功,会返回一个标识这个套接字的文件描述符,失败的时候返回-1。

domain,函数socket()的参数domain用于设置网络通信的域,函数socket()根据这个参数选择通信协议的族,常用AF_INET。

type,函数socket()的参数type用于设置套接字通信的协议类型,主要有SOCKET_STREAM(流式套接字)(Tcp连接,提供序列化的、可靠的、双向连接的字节流。支持带外数据传输)、SOCK——DGRAM(数据包套接字)(支持UDP连接(无连接状态的消息))等。

protocol,函数socket()的第3个参数protocol用于制定某个协议的特定类型,即type类型中的某个类型。通常某协议中只有一种特定类型,这样protocol参数仅能设置为0;但是有些协议有多种特定的类型,就需要设置这个参数来选择特定的类型。

errno,函数socket()并不总是执行成功,有可能会出现错误,错误的产生有多种原因,可以通过errno获得,头文件#include <errno.h>

返回值,如果成功返回非负描述符,不成功返回-1

2.bind

int bind(int sockfd,const struct sockaddr* myaddr,socklen_t addrlen), 当socket函数返回一个描述符时,只是存在于其协议族的空间中,并没有分配一个具体的协议地址(这里指IPv4/IPv6和端口号的组合),bind函数可以将一组固定的地址绑定到sockfd上。

sockfd是socket函数返回的描述符;

myaddr指定了想要绑定的IP和端口号,均要使用网络字节序-即大端模式;

addrlen是前面struct sockaddr(与sockaddr_in等价)的长度。

为了统一地址结构的表示方法,统一接口函数,使得不同的地址结构可以被bind()、connect()、recvfrom()、sendto()等函数调用。但一般的编程中并不直接对此数据结构进行操作,而使用另一个与之等价的数据结构sockaddr_in。例如:

struct sockaddr_in servaddr;

memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(9999);

bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr))

通常服务器在启动的时候都会绑定一个众所周知的协议地址,用于提供服务,客户就可以通过它来接连服务器;而客户端可以指定IP或端口也可以都不指定,未分配则系统自动分配。这就是为什么通常服务器端在listen之前会调用bind(),而客户端就不会调用,而是在connect()时由系统随机生成一个。sockfd的分配是一个bigmap的做法

3.listen

int listen(int sockfd, int backlog),返回0表示成功,-1表示失败

函数listen仅被tcp服务器调用,做两件事情:

1.当函数socket创建一个套接口时,它被假设为一个主动套接口,也就是说,它是一个将调用connect发起连接的客户套接口,函数listen将未连接的套接口转换成被动套接口,指示内核应接受指向此套接口的连接请求。调用函数listen导致套接口从CLOSED状态转换到LISTEN状态。

2.函数的第二个参数规定了内核为此套接口排队的最大连接个数。

一般来说,此函数应在调用幻术socket和bind之后,调用函数accept之前调用。

对于给定的监听套接口,内核要维护两个队列:

1.未完成连接队列,为每个这样的SYN分别开设一个条目:已由客户发出并到达服务器,服务器正在等待完成相应的TCp三次握手过程,这些套接口都处于SYN-RCVD状态;

2.已完成连接队列:为每个已完成TCP三次握手过程的客户开设一个条目。这些套接口都处于ESTABLISHED状态。

两个队列之和数量不得超过backlog。

4.connect

int connect(int sockfd,conststruct sockaddr *addr, socklen_t addrlen)返回0成功,-1表示失败。

通过此函数建立于TCP服务器的连接,实际是发起三次握手过程,仅在连接成功或失败后返回。参数sockfd是本地描述符,addr为服务器地址,addrlen是socket地址长度。

UDP的connect函数,结果与tcp调用不相同,没有三次握手过程。内核只是记录对方的ip和端口号,他们包含在传递给connect的套接口地址结构中,并立即返回给调用进程。

5.accept

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)返回值非负描述符表示成功,-1表示失败。

6.send

size_t send(int sockfd, const void *buf, size_t len, int flags) 返回值成功返回成功拷贝至发送缓冲区的字节数(可能小于len),-1表示失败;

其中:

sockfd:发送端套接字描述符(非监听描述符)

buf:应用要发送数据的缓存 (#define MAXLNE 4096 char buf[MAXLNE];)

len:实际要发送的数据长度

flag:一般设置为0

每个TCP套接口都有一个发送缓冲区,它的大小可以用SO_SNDBUF这个选项来改变。调用send函数的过程,实际是内核将用户数据拷贝至TCP套接口的发送缓冲区的过程:若len大于发送缓冲区大小,则返回-1;否则,查看缓冲区剩余空间是否容纳得下要发送的len长度,若不够,则拷贝一部分,并返回拷贝长度(指的是非阻塞send,若为阻塞send,则一定等待所有数据拷贝至缓冲区才返回,因此阻塞send返回值必定与len相等);若缓冲区满,则等待发送,有剩余空间后拷贝至缓冲区;若在拷贝过程出现错误,则返回-1。关于错误的原因,查看errno的值。

如果send在等待协议发送数据时出现网络断开的情况,则会返回-1。注意:send成功返回并不代表对方已接收到数据,如果后续的协议传输过程中出现网络错误,下一个send便会返回-1发送错误。TCP给

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值