文章目录
- 1、概述
- 2、connect函数
- 3、listen函数
- 4、accept返回值处理
- 5、recv返回值处理
- 5.1、LT\ET模式读取数据
- 6、send返回值处理
1、概述
主要介绍网络编程中,使用到的一些系统调用解释,以及返回值的说明
2、connect函数
connect函数功能为,客户端主动向服务器发起连接请求,建立连接时通过三次握手,这个三次握手的过程时由TCP协议栈完成的,不是这个函数做的,这个函数只是通知协议栈要进行三次握手了,这个函数会阻塞等待,三次握手成功或者失败超时则返回
int connectfd = socket(AF_INET, SOCK_STREAM, 0);
int ret = connect(connectfd, (struct sockaddr *)&addr, sizeof(addr));
// ret == -1 && errno == EINPROGRESS 正在建立连接
// ret == -1 && errno = EISCONN 连接建立成功
正在建立连接中
连接建立成功
3、listen函数
listen函数 主要是服务端,用来被动监听套接字上是否有连接请求,backlog参数,主要是用来设置内核中队列大小,不同系统含义不同,Linux中,这个参数表示已完成连接队列大小,如果时mac系统,这个参数表示的是已完成队列和未完成队列的和,未完成队列:主要存放,发送第一次握手的客户端,完成队列:主要存放,完成三次握手的客户端。accept函数也是直接取完成队列中取
4、accept返回值处理
EAGAIN
对accept、send和recv而言,事件未发生时errno通常被设置成EAGAIN(意为“再来一次”)或者EWOULDBLOCK(意为“期待阻塞”),accept()没准备好,这个EAGAIN错误EWOULDBLOCK是一样的
ECONNABORTED
ECONNRESET错误则发生在对方意外关闭套接字后【您的主机中的软件放弃了一个已建立的连接–由于超时或者其它失败而中止接连(用户插拔网线就可能有这个错误出现)】,该错误被描述为“software caused connection abort”,即“软件引起的连接中止”。原因在于当服务和客户进程在完成用于 TCP 连接的“三次握手”后,客户 TCP 却发送了一个 RST (复位)分节,在服务进程看来,就在该连接已由 TCP 排队,等着服务进程调用 accept 的时候 RST 却到达了。POSIX 规定此时的 errno 值必须 ECONNABORTED。源自 Berkeley 的实现完全在内核中处理中止的连接,服务进程将永远不知道该中止的发生。服务器进程一般可以忽略该错误,直接再次调用accept。
EMFILE或者ENFILE
EMFILE:进程的fd已用尽【已达到系统所允许单一进程所能打开的文件/套接字总数】
ENOSYS
accept4()函数没实现
ECONNABORTED
对方关闭套接字
5、recv返回值处理
recv返回值为0
表示客户端正常完成4次挥手断开连接
errno == EAGAIN || errno == EWOULDBLOCK
EAGAIN和EWOULDBLOCK[【这个应该常用在hp上】应该是一样的值,表示没收到数据,一般来讲,在ET模式下会出现这个错误,因为ET模式下是不停的recv肯定有一个时刻收到这个errno,但LT模式下一般是来事件才收,所以不该出现这个返回值,不当做错误处理,只是简单返回
errno == EINTR
EINTR错误的产生:当阻塞于某个慢系统调用的一个进程捕获某个信号且相应信号处理函数返回时,该系统调用可能返回一个EINTR错误,我认为LT模式不该出现这个errno,而且这个其实也不是错误,所以不当做错误处理
errno == ECONNRESET
如果客户端没有正常关闭socket连接,却关闭了整个运行程序【真是够粗暴无理的,应该是直接给服务器发送rst包而不是4次挥手包完成连接断开】,那么会产生这个错误
errno == EBADF
因为多线程,偶尔会干掉socket,所以不排除产生这个错误的可能性
5.1、LT\ET模式读取数据
LT模式
m_read_idx当前读了多少字节
m_read_buf 存储读取数据的数组
READ_BUFFER_SIZE 最多读取这么多
因为LT模式主要读缓冲区中有内容就会一直触发,所以每次读取完之后立刻返回
ET模式
因为ET模式,是不管你有没有处理这个消息都只会触发一次,所以我们需要一直读,直到将数据全部读取完才退出
if (m_read_idx >= READ_BUFFER_SIZE)
{
return false;
}
if(m_read_idx<0)
return false;
int bytes_read = 0;
//LT读取数据
if (0 == m_TRIGMode)
{
bytes_read = recv(m_sockfd, m_read_buf + m_read_idx, READ_BUFFER_SIZE - m_read_idx, 0);
m_read_idx += bytes_read;
if (bytes_read <= 0)
{
return false;
}
//printf("bytes_read:%d\n",bytes_read);
// printf("读取全部数据:%s\n",m_read_buf);
return true;
}
//ET读数据
else
{
while (true)
{
bytes_read = recv(m_sockfd, m_read_buf + m_read_idx, READ_BUFFER_SIZE - m_read_idx, 0);
if (bytes_read == -1)
{
if (errno == EAGAIN || errno == EWOULDBLOCK)
break;
return false;
}
else if (bytes_read == 0)
{
return false;
}
m_read_idx += bytes_read;
}
return true;
}
6、send返回值处理
send返回值为0
表示客户端正常完成4次挥手断开连接
errno == EAGAIN
内核缓冲区满,这个不算错误
errno == EINTR
这个应该也不算错误 ,收到某个信号导致send产生这个错误