设置成非阻塞模式:
先用fcntl的F_GETFL获取flags,用F_SETFL设置flags|O_NONBLOCK;
即:
flags = fcntl(sockfd, F_GETFL, 0); //获取文件的flags值。
fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); //设置成非阻塞模式;
同时在接收和发送数据时,需要使用MSG_DONTWAIT标志
即:
在recv,recvfrom和send,sendto数据时,将flag设置为MSG_DONTWAIT。
设置成阻塞模式:
先用fcntl的F_GETFL获取flags,用F_SETFL设置flags&~O_NONBLOCK;
即:
flags = fcntl(sockfd,F_GETFL,0); //获取文件的flags值。
fcntl(sockfd,F_SETFL,flags&~O_NONBLOCK); //设置成阻塞模式;
同时在接收和发送数据时,需要使用阻塞标志
即:
在recv,recvfrom和send,sendto数据时,将flag设置为0,默认是阻塞。
在将socket设置成非阻塞模式后,每次的对于sockfd 的操作都是非阻塞的;
非阻塞模式下:
connect
=0 当返回0时,表示立即创建了socket链接,
<0 当返回-1时,需要判断errno是否是EINPROGRESS(表示当前进程正在处理),否则失败。
例如:下面会有select或epoll监听fd是否建立链接,
select监听connect是否成功的例子,注意getsockopt验证,因为三次握手的第三个ACK有可能会丢失,但是客户端认为链接已经建立:
int ret = ::connect(_socket_fd, add.addr(), add.length());
if(ret == 0)
{
//建立链接成功
}
else if(ret < 0 && errno == EINPROGRESS) //errno == EINPROGRESS表示正在建立链接
{
// 等待连接完成,errno == EINPROGRESS表示正在建立链接
fd_set set;
FD_ZERO(&set);
FD_SET(_socket_fd,&set); //相反的是FD_CLR(_sock_fd,&set)
time_t = 10; //(超时时间设置为10毫秒)
struct timeval timeo;
timeo.tv_sec = timeout / 1000;
timeo.tv_usec = (timeout % 1000) * 1000;
int retval = select(_socket_fd + 1, NULL, &set, NULL, &timeo); //事件监听
if(retval < 0)
{
//建立链接错误close(_socket_fd)
}
else if(retval == 0) // 超时
{
//超时链接没有建立close(_socket_fd)
}
//将检测到_socket_fd读事件或写时间,并不能说明connect成功
if(FD_ISSET(_socket_fd,&set))
{
int error = 0;
socklen_t len = sizeof(error);
if(getsockopt(_socket_fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
{
//建立简介失败close(_socket_fd)
}
if(error != 0) // 失败
{
//建立链接失败close(_socket_fd)
}
else
{
//建立链接成功
}
}
}
else
{
//出现错误 close(_sock_fd)
}
注意:这里主要是想强调当epoll或select监听到sockfd上有EPOLL_IN或EPOLL_OUT时,即读写事件时,并不能说明链接已经建立,如上面的代码。
/*
int error = 0;
socklen_t ilen = sizeof(error);
ret = getsockopt(fd,SOL_SOCKET,SO_ERROR,&error,&ilen);
if(ret < 0)
{
//说明链接建立失败,close(fd);
}
else if(error != 0 )
{
//说明链接建立失败,close(fd);
}
else
{
//说明链接建立成功。即可以向fd上写数据。
}
*/
recv 和 recvfrom
=0 当返回值为0时,表示对端已经关闭了这个链接,我们应该自己关闭这个链接,即close(sockfd)。另外因为异步操作会用select或epoll做事件触发,所以:
1、如果使用select,应该使用FD_CLR(sockfd,fd_set)将sockfd清除掉,不再监听。
2、如果使用epoll,系统会自己将sockfd清除掉,不再进行监听。
>0 当返回值大于0 且 小于sizeof(buffer)时,表示数据肯定读完。(如果等于sizeof(buffer),可能有数据还没读,应该继续读,不可能有大于)
<0 当返回值小于0,即等于-1时,分情况判断:
1、如果 errno 为 EAGAINE 或 EWOULDBLOCK
表示暂时无数据可读,可以继续读,或者等待epoll或select的后续通知。(EAGAINE,EWOULDBLOCK产生的
原因:可能是多进程读同一个sockfd,可能一个进程读到数据,其他进程就读取不到数据(类似惊群效应),当然
单个进程也可能出现这种情况。对于这种错误,不需用close(sockfd)。可以等待select或epoll的下一次触发,
继续读。)
2、如果 errno 为 EINTR
表示被中断了,可以继续读,或者等待epoll或select后续的通知。
否则,真的是读取数据失败。(此时应该close(sockfd))
send和sendto
返回值是实际发送的字符数,因为我们知道要发送的总长度,所以,如果没有发送完,我们可以继续发送。
<0 当返回值为 -1 时, 我们需要判断 errno:
1、如果errno为 EAGAINE 或 EWOULDBLOCK ,表示当前缓冲区写满,可以继续写,
或者等待epoll或select的后续通知,一旦有缓冲区,就会触发写操作,这个也是经常利用的一个特性。
2、如果errno为EINTR ,表示被中断了,可以继续写,或者等待epoll或select的后续通知。
否则真的出错了,即errno不为EAGAINE或EWOULDBLOCK或EINTR,此时应该close(sockfd)
>=0 >=0且不等于要求发送的长度,应该继续send,如果等于要求发送的长度,发送完毕。
相关推荐
WinSock 支持两种主要的执行模式:阻塞模式(Blocking Mode)和非阻塞模式(Non-blocking Mode)。 - **阻塞模式**:当应用程序调用某个函数时,该调用会一直等待直至满足条件或获得所需数据后才返回。在此期间,...
同时,考虑到网络通信的异步性质,可能需要使用阻塞和非阻塞模式,或者配合多线程、异步I/O等技术来处理网络事件。 八、网络编程实践 通过实际编写server-new.cpp和client-new.cpp,你可以学习如何在VC 2008环境下...
- `recv`/`recvfrom`: 从连接或非连接套接字接收数据。 - `send`/`sendto`: 发送数据到连接或非连接套接字。 - `select`: 检查多个套接字是否已准备好进行读写操作。 - **套接字配置相关:** - `bind`: 将套接字...
- **异步IO或事件驱动**:另一种方式是使用非阻塞的socket,配合事件循环和回调函数,或者使用Python的asyncio库进行异步处理。 6. **关闭Socket**: - 通信完成后,应使用`close()`方法关闭socket,释放资源。...
在Windows环境下,C语言是...理解这些基本操作后,可以进一步学习更复杂的网络编程概念,如多线程、异步通信、套接字选项等。对于初学者,建议从简单的客户端-服务器模型开始,逐步深入,掌握Socket编程的核心技巧。
其中,WSAAsyncGetHostByAddr等函数用于异步获取主机信息,WSAAsyncSelect用于设置Socket的异步事件通知,WSACancelBlockingCall用于取消当前阻塞的Socket操作。 关于阻塞和非阻塞模式: - **阻塞模式**:调用函数...
- 对于性能优化,除了多线程,还可以考虑使用非阻塞I/O(`socket.setblocking(False)`)或异步I/O(如`asyncio`库)。 以上就是使用Python的socket模块实现服务端和客户端之间网络通信的基本原理和关键步骤。实际...
- **网络I/O函数**:如`accept`(接受连接请求)、`closesocket`(关闭套接字)、`connect`(发起连接请求)、`recv`(接收数据)、`recvfrom`(接收来自特定地址的数据)、`select`(监控多个套接字的状态)、`...
在IT领域,Socket编程是网络通信的核心技术之一,它允许两个或多个应用程序通过网络进行数据交换。本篇文章将深入探讨如何在Visual Studio 2008(VS2008)环境中实现Socket通信,这对于开发跨平台的网络应用至关重要...
一类涉及网络I/O,如`accept`, `close`, `connect`, `recv`, `recvfrom`, `select`, `send`, `sendto`;另一类不涉及网络I/O,如`bind`, `getpeername`, `getsockname`, `getsockopt`, `htonl`, `htons`, `inet_addr...
5. **非阻塞模式**:在Socket编程中,非阻塞模式允许Socket在没有数据可读或无法立即写入时不会被阻塞,而是立即返回一个错误。这种方式常用于提高程序的效率,特别是在处理大量并发连接时。 6. **套接字(Socket)...
目的是让初学者不仅对Socket异步非阻塞的概念有个非常透彻的理解,而且也给他们提供一个用Socket开发网络通信应用程序的快速入门方法。操作系统是Windows 98(或NT4.0),开发工具是Visual C++6.0。 MFC提供了一个...
- `fcntl` 和 `ioctl` 函数:实现异步I/O、非阻塞I/O等功能。 #### 三、ACE_Socket的特点与优势 ACE_Socket 提供了对传统Socket API 的封装,具有以下特点: - **跨平台性**:支持多种操作系统,包括Unix、Linux...
Socket编程是计算机网络通信中的重要概念,主要用于实现进程间的网络通信。在本压缩包"socket-2.zip"中,我们可能会找到与Socket编程相关的网页、文档或其他资源,这些资料可以帮助我们深入理解Socket的工作原理和...
而C++服务端可以采用阻塞或非阻塞模式,取决于具体实现。 为了确保通信的可靠性,开发者需要考虑以下几点: 1. **错误处理**:在网络通信中,错误是常见的,如连接断开、数据传输错误等。客户端和服务端都需要适当...
- **soc_setsockopt**:设置Socket选项,如非阻塞模式和异步I/O。 - **soc_connect**:用于连接指定的服务器。仅面向连接的Socket(如TCP)需要使用。 - **soc_send**/**soc_recv**:分别用于发送和接收数据。其中`...
- **同步与异步**:CSocket 主要用于实现同步 Socket 通信,而 CAsyncSocket 则用于实现异步通信。 - **事件处理**:CSocket 需要显式地调用 `recv` 或 `send` 函数来读取或发送数据,而 CAsyncSocket 会自动调用...
通过缓存、非阻塞I/O、异步I/O等方式,可以提升Socket通信的性能,降低延迟,提高系统吞吐量。 10. **网络编程库**: 有许多第三方库如Boost.Asio、libevent、libuv等,提供了更高级别的抽象,简化了Socket编程的...
在并发环境下,`accept()`函数通常会阻塞,直到有新的连接到达,因此可能需要非阻塞模式或线程池来处理并发连接。 6. **关闭Socket** 数据传输完成后,记得调用`close()`函数关闭Socket,释放资源。 7. **异常...