一.服务器socket端口绑定失败
问题
在学习socket的使用,服务器使用的是libevent框架,绑定和监听的是服务器的私网ip以及8000端口号。
运行程序却输出打印信息:"bind error"。
//初始化监听 socket 并开始监听客户端连接
void Server::listen(const char *ip, int port)
{
//指定服务器的监听地址和端口。
struct sockaddr_in server_info;
int len = sizeof(server_info);
//初始化结构体,确保没有不必要的垃圾数据。
memset(&server_info, 0, len);
server_info.sin_family = AF_INET;
server_info.sin_port = htons(port);
server_info.sin_addr.s_addr = inet_addr(ip);
//evconnlistener_new_bind函数会创建一个监听TCP连接的监听器,并将其与事件基(m_base)进行绑定。
struct evconnlistener *listener = evconnlistener_new_bind(m_base,
listener_cb, this, LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE,
5, (struct sockaddr *)&server_info, len);
if (NULL == listener)
{
std::cout << "bind error" << std::endl;
return;
}
//启动定时器并监听
event_base_dispatch(m_base);
//释放对象
evconnlistener_free(listener);
event_base_free(m_base);
}
解决问题:
1.是否端口号被占用:
使用sudo lsof -i :8000检测。
=》检测到端口无占用。
2.云服务器上是否在安全组上开放了这个端口
检查结果为开放了。
3.查看防火墙设置:
sudo ufw status 输出:
Status: inactive 故没有错误。
4.加上一些打印信息:
inet_addr
返回的是一个 in_addr_t
类型的值。如果无法解析传入的 IP 地址,它将返回 INADDR_NONE
。 故我加上了:
server_info.sin_addr.s_addr = inet_addr(ip);
if (server_info.sin_addr.s_addr == INADDR_NONE) {
std::cerr << "Invalid IP address: " << ip << std::endl;
return;
}
但是我发现ip地址没有错。
故我在 evconnlistener_new_bind
函数后使用 perror
输出详细的错误信息。即:
if (NULL == listener)
{
std::cout << "bind error" << std::endl;
return;
}
却输出
bind error: Address already in use
bind error
这不是和第一点矛盾了吗?
再使用下面命令查看 当前系统中占用的端口和进程
sudo lsof -i
输出:
main 6906 root 6u IPv4 128322 0t0 TCP iZ7xv4i5mr54tgr8r3f9cqZ:8000 (LISTEN)
这里有一个名为 main
的进程,PID 为 6906
,它正在监听端口 8000
。
而后发现原来我第一步把8000打错为8080。(手误)
从而我决定杀死这个PID。
kill -9 6906
终于问题解决了!
二.头文件被多重包含解决
#ifndef SERVER_H
和 #define SERVER_H
是防止头文件被多重包含的常见做法。每次包含该头文件时,首先检查是否已经定义了 SERVER_H
,如果没有定义则进行定义并包含文件内容。