lesson40 聊天室改成多线程
线程池内部处理任务时候已经解锁了,所以函数中成员集不属于临界资源,多线程访问会出现问题
可以把route新增,转发,删除在udpserver拆开,这样的话锁的力度就变细了。
看网络第二个课件的补充参考部分 改一下Inetaddr.hpp 主机转网络封装好了之后,sockaddr_in就不需要初始化各种值,肢解创建InetAddr,直接就初始化好了。
inet_ntoa有可能存在线程安全问题 ip以后用inet_ntop inet_pton 端口用ntohs htons
windows linux能联动
看tcpechoserver代码
服务器禁止拷贝
继承之后如果想拷贝,必须拷贝父类,父类禁止拷贝所以就禁止拷贝
telnet 可以远程连接tcp服务器 telnet ip 端口号

cpp
#pragma once
// 注意:基于截图内容,省略了外部头文件(如 <iostream>, <unistd.h>, "Log.hpp", "InetAddr.hpp" 等)
// 假设 backlog 和 CONV 宏已在 Common.hpp 等文件中定义
// const static int backlog = 16;
// #define CONV(addr) (struct sockaddr *)&(addr)
// 服务器往往是禁止拷贝的
using namespace LogModule;
const static int defaultsockfd = -1;
class TcpServer : public NoCopy
{
public:
TcpServer(uint16_t port) : _port(port), _listensockfd(defaultsockfd), _isrunning(false)
{}
void Init()
{
// 1. 创建套接字文件
_listensockfd = socket(AF_INET, SOCK_STREAM, 0);
if (_listensockfd < 0)
{
LOG(LogLevel::FATAL) << "socket error";
exit(SOCKET_ERR);
}
LOG(LogLevel::INFO) << "socket success: " << _listensockfd; // 3
// 2. bind众所周知的端口号
InetAddr local(_port);
int n = bind(_listensockfd, local.NetAddrPtr(), local.NetAddrLen());
if (n < 0)
{
LOG(LogLevel::FATAL) << "bind error";
exit(BIND_ERR);
}
LOG(LogLevel::INFO) << "bind success: " << _listensockfd; // 3
// 3. 设置socket状态为listen
n = listen(_listensockfd, backlog);
if (n < 0)
{
LOG(LogLevel::FATAL) << "listen error";
exit(LISTEN_ERR);
}
LOG(LogLevel::INFO) << "listen success: " << _listensockfd; // 3
}
void Service(int sockfd, InetAddr &peer)
{
char buffer[1024];
while (true)
{
// 1. 先读取数据
// a. n>0: 读取成功
// b. n<0: 读取失败
// c. n==0: 对端把链接关闭了,读到了文件的结尾 --- pipe
ssize_t n = read(sockfd, buffer, sizeof(buffer) - 1);
if (n > 0)
{
buffer[n] = 0; // 设置为C风格字符串,n<= sizeof(buffer)-1
LOG(LogLevel::DEBUG) << peer.StringAddr() << " say# " << buffer;
// 2. 写回数据
std::string echo_string = "echo# ";
echo_string += buffer;
write(sockfd, echo_string.c_str(), echo_string.size());
}
else if (n == 0)
{
LOG(LogLevel::DEBUG) << peer.StringAddr() << " 退出了...";
close(sockfd);
break;
}
else
{
LOG(LogLevel::DEBUG) << peer.StringAddr() << " 退出了...";
close(sockfd);
break;
}
}
}
void Run()
{
_isrunning = true;
while (_isrunning)
{
// a. 获取链接
struct sockaddr_in peer;
socklen_t len = sizeof(sockaddr_in);
// 如果没有连接,accept就会阻塞
int sockfd = accept(_listensockfd, CONV(peer), &len);
if (sockfd < 0)
{
LOG(LogLevel::WARNING) << "accept error";
continue;
}
InetAddr addr(peer);
LOG(LogLevel::INFO) << "accept success, peer addr : " << addr.StringAddr();
// version0 -- test version --- 单进程程序 --- 不会存在的!
Service(sockfd, addr);
}
_isrunning = false;
}
~TcpServer()
{
}
private:
uint16_t _port;
int _listensockfd; // 监听socket
bool _isrunning;
};

