原生socket编写服务端close后立即bind失败,原因socket会延迟关闭,解决方案--设置端口复用
self.fd = socket(AF_INET,SOCK_STREAM,0);
int opt = 1;
setsockopt(_fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&opt, sizeof(opt));
self.server_addr = inet_addr("127.0.0.1");
//set server addr info
struct sockaddr_in server_addr;
bzero(&server_addr, sizeof(struct sockaddr_in));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(port);
if(bind(self.fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0){
DTLogError(@"bind error\n");
return -1;
}
if(listen(self.fd, 65535) < 0){
DTLogError(@"listen error\n");
return -2;
}
关于kqueue
//创建Kqueue结构体数组
struct kevent change_event[1024],event[1024];
//创建对端地址结构体
struct sockaddr_in client_addr;
size_t client_len = sizeof(struct sockaddr_in);
// Prepare the kqueue.
int kq = kqueue();
//Set listen fd
int fd = self.fd;
//添加服务端fd,以监听连接syn
EV_SET(change_event, fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0);
// 注册kqueue监听
if (kevent(kq, change_event, 1, NULL, 0, NULL) == -1)
{
perror("kevent");
return;
}
self.status = YES;
while (self.status)
{
// 获取事件
int new_events = kevent(kq, NULL, 0, event, 1, NULL);
//时间数为-1则获取失败,退出循环
if (new_events == -1)
{
perror("kevent");
self.status = NO;
}
//遍历事件
for (int i = 0; new_events > i; i++)
{
//获取事件的描述符
int event_fd = (int)event[i].ident;
//如果描述符和监听描述符一致,则为客户端连接请求
if (event_fd == fd)
{
// Accept客户端,获取与该客户端连接的FD
int socket_connection_fd = accept(event_fd, (struct sockaddr *)&client_addr, (socklen_t *)&client_len);
if (socket_connection_fd == -1)
{
perror("Accept socket error");
}
//添加fd到kqueue监听
EV_SET(change_event, socket_connection_fd, EVFILT_READ, EV_ADD, 0, 0, NULL);
if (kevent(kq, change_event, 1, NULL, 0, NULL) < 0)
{
perror("kevent error");
}
}else{
//连接终止
if (event[i].flags & EV_EOF)
{
//关闭socket
close(event_fd);
}
else if (event[i].filter & EVFILT_READ)
{
//此时您可以调用read()去读取数据,可以在循环的任意处写,但是不能异步调用,可以用一个专用socket与本监听通信间接写保证安全
}
}
}