大并发服务器不得不说的技术--connect 异步
前面我们谈的大多是服务端与客户端的技术,服务器开发其实有时还会涉及到跨服务器的访问,比如腾讯的拍拍服务器需要知道登录的会员信息,
就需要访问会员服务器。
跨务器访问会涉及到很多的技术,比如访问权限控制,数据同步等,这里主要来学习一下传输层。
为了更容易理解,我们将访问端服务器称为客户端,被访问端服务器称为服务端。
客户端发起一个连接的过程:
socket_fd = socket( AF_INET,SOCK_STREAM,0 );
ret = connect( socket_fd, (sockaddr*)&addr, sizeof(addr) );
问题就出在第二步,connect 如果是同步的,如果服务端很忙,客户端就会一直阻塞在这里,最多有可能会耗上几十秒,开玩笑,不会吧,客户端也是个服务器唉,
敢情这块不就成了瓶颈吗。
我们来理清下思路:
就像你跟人家姑娘表白了,姑娘说今天不告诉你答案,明天打电话再告诉你,你是不是要一直不吃不喝在她家楼下等呢,还是回去好好休息等她电话。
够明白了么,我建议还是回家休息去吧,因为你还有很多很重要的事做呢。
同样的思路,客户端需要想办法把这个差事放进某个通知队列中。
解决这个问题就是在connect 前先要将 socket_fd 设为异步的(nonblocking):
fcntl(socket_fd, F_SETFL, fcntl(s, F_GETFL) | O_NONBLOCK);
连接的时候如果暂时连不上,connect 返回-1,好家伙,人家姑娘害羞呢,但又不表示拒绝。
那行吧,在家等电话,先要把人家姑娘号码存起来吧。
在咱们这里就是将 socket_fd 放到通知队列中,以epoll 为例,
struct epoll_event ee;
ee.events = EPOLLOUT | EPOLLET;
ee.data.fd = socket_fd;
epoll_ctl( epfd, EPOLL_CTL_ADD, socket_fd, &ee );
现在该干什么干什么去吧。
电话来了, 再做相应处理,应该高兴还是悲伤,表情函数预备下,免得到时大脑真空。
不同的是如果姑娘告诉你她答应你了事情就算完了,而epoll 回调告诉你有事件了你还需要确认一下:
getsockopt(socket_fd SOL_SOCKET, SO_ERROR, &error, (socklen_t *)&len);
if( !error )
{
//OK
}
或者也可以使用 getsockname或getpeername,确认OK了才表示连接成功了。