电子波尔多进程
epoll multi process
本文关键字:多进程 更新时间:2023-10-16
我继续学习使用 c/c++ 进行网络编程,之后我创建了多进程 tcp 服务器,我想创建简单的 http 服务器,它返回静态资源,我使用 epoll,所以让我展示我的代码
首先,我在工人中使用 fd 传递来处理请求所以,我的主要功能和头部过程
struct Descriptors{
int sv[2];
};
class Parent{
public:
static Parent& getInstance(){
static Parent instance;
return instance;
}
Parent(Parent const&) = delete;
void operator=(Parent const&) = delete;
void addFd(int fd){
m_fd.push_back(fd);
};
void run() {
startServer();
size_t index = 0;
while(true){
struct epoll_event Events[MAX_EVENTS];
int N = epoll_wait(m_epoll, Events, MAX_EVENTS, -1);
for (size_t i =0; i < N; ++i){
if (Events[i].events & EPOLLHUP){
epoll_ctl(m_epoll, EPOLL_CTL_DEL, Events[i].data.fd, &(Events[i]));
shutdown(Events[i].data.fd,SHUT_RDWR);
close(Events[i].data.fd);
continue;
}else {
if (Events[i].data.fd == m_masterSocket) {
handleConnection();
}else {
char * arg = "1";
ssize_t size = sock_fd_write(m_fd[index], arg, 1,Events[i].data.fd);
index = (1+index) % m_fd.size();
}
}
}
}
}
private:
Parent(){
m_numCpu = sysconf(_SC_NPROCESSORS_ONLN);
}
void startServer(){
m_masterSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
struct sockaddr_in SockAddr;
SockAddr.sin_family = AF_INET;
SockAddr.sin_port = htons(11141);
SockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
bind(m_masterSocket, (struct sockaddr *)(&SockAddr), sizeof(SockAddr));
set_nonblock(m_masterSocket);
listen(m_masterSocket, SOMAXCONN);
m_epoll = epoll_create1(0);
struct epoll_event Event;
Event.data.fd = m_masterSocket;
Event.events = EPOLLIN | EPOLLRDHUP;
epoll_ctl(m_epoll, EPOLL_CTL_ADD, m_masterSocket, &Event);
}
void handleConnection(){
int SlaveSocket = accept(m_masterSocket, 0, 0);
set_nonblock(SlaveSocket);
struct epoll_event Event;
Event.data.fd = SlaveSocket;
Event.events = EPOLLIN | EPOLLRDHUP;
epoll_ctl(m_epoll, EPOLL_CTL_ADD, SlaveSocket, &Event);
}
int m_epoll;
int m_masterSocket;
int m_numCpu;
std::vector<int> m_fd;
};
void parent(int sock){
Parent::getInstance().addFd(sock);
}
int main(int argc, char **argv){
int numCpu = sysconf(_SC_NPROCESSORS_ONLN);
std::vector<Descriptors> desc;
desc.resize(numCpu);
bool isParent = true;
for (int i = 0; i < numCpu && isParent; ++i){
std::cout << "pid my is = " << getpid() <<std::endl;
int sv[2];
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) < 0) {
perror("socketpair");
exit(1);
}
pid_t forkId = fork();
switch (forkId){
case 0:{
isParent = false;
close(sv[0]);
child(sv[1]);
break;
}
case -1:
perror("fork");
exit(1);
default:
close(sv[1]);
parent(sv[0]);
break;
}
}
if (isParent){
Parent::getInstance().run();
int status;
waitpid(-1, &status, 0);
}
}
我的工作过程是
void respond(int fd)
{
char mesg[99999], *reqline[3], data_to_send[BYTES], path[99999];
int rcvd, fileDesc, bytes_read;
memset( (void*)mesg, (int)' ', 99999 );
const char *ROOT = "/home/web_server/";
int RecvResult = recv(fd,mesg, 99999, MSG_NOSIGNAL);
if (RecvResult == 0 && errno != EAGAIN){
shutdown(fd,SHUT_RDWR);
close(fd);
}else if (RecvResult >0){
printf("%s", mesg);
reqline[0] = strtok (mesg, " tn"); // split on lexemes
if ( strncmp(reqline[0], "GET ", 4)==0 ) // if first 4 character equal
{
reqline[1] = strtok (NULL, " t");
reqline[2] = strtok (NULL, " tn");
std::cout << "reqline 1 " << reqline[1] << std::endl;
std::cout << "reqline 2 " << reqline[2] << std::endl;
if ( strncmp( reqline[2], "HTTP/1.0", 8)!=0
&& strncmp(reqline[2], "HTTP/1.1", 8 ) !=0 )
{
write(fd, "HTTP/1.0 400 Bad Requestn", 25);
}
else
{
if ( strncmp(reqline[1], "/ ", 2)==0 )
reqline[1] = "/index.html";
strcpy(path, ROOT);
strcpy(&path[strlen(ROOT)], reqline[1]);
printf("file: %sn", path);
if ( (fileDesc=open(path, O_RDONLY))!=-1 )
{
send(fd, "HTTP/1.0 200 OKnn", 17, 0);
while ( (bytes_read=read(fileDesc, data_to_send, BYTES))>0 )
write (fd, data_to_send, bytes_read);
}
else write(fd, "HTTP/1.0 404 Not Foundn", 23);
}
}
}
shutdown(fd,SHUT_RDWR);
close(fd);
}
void child(int sock)
{
int fd;
char buf[16];
ssize_t size;
sleep(1);
for (;;) {
size = sock_fd_read(sock, buf, sizeof(buf), &fd);
if (size <= 0)
break;
if (fd != -1) {
respond(fd);
}
}
printf("child processes is endn");
}
当我进入浏览器 http://127.0.0.1:11141/没关系,我得到索引.html,但是当我在 apache 基准测试中运行时,作为
ab -n 10 -c 10 http://127.0.0.1:11141/
我得到的答案是
This is ApacheBench, Version 2.3
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking 127.0.0.1 (be patient)...apr_socket_recv: Connection reset by peer (104)
Total of 2 requests completed
我不明白我的错误在哪里,因为我认为我的服务器理论上(因为使用 epoll )必须解决 C10K 问题。 但在实践中,我的服务器无法解析 10 个连接。你能帮我吗?感谢您提供有用的链接和任何建议!
更新当我运行为
strace -f ./server 2> error.txt
错误结束时.txt
[pid 6552] write(6, 0x7ffdbff00390, 757) = -1 EPIPE (Broken pipe)
[pid 6552] --- SIGPIPE {si_signo=SIGPIPE, si_code=SI_USER, si_pid=6552, si_uid=1000} ---
[pid 6552] +++ killed by SIGPIPE +++
write(1, 0x7fc5ffbe3000, 83) = 83
write(1, 0x7fc5ffbe3000, 12) = 12
write(1, 0x7fc5ffbe3000, 20) = 20
write(1, 0x7fc5ffbe3000, 41) = 41
open(0x7ffdbff18e30, O_RDONLY) = 11
sendto(10, 0x403df9, 17, 0, NULL, 0) = 17
read(11, 0x7ffdbff00390, 1024) = 757
write(10, 0x7ffdbff00390, 757) = -1 EPIPE (Broken pipe)
--- SIGPIPE {si_signo=SIGPIPE, si_code=SI_USER, si_pid=6554, si_uid=1000} ---
+++ killed by SIGPIPE +++
所以我认为EPipe错误中的那个问题,但我不明白为什么...
更新
所以我认为这个问题在描述中很接近,但我不明白如何解决它。感谢您的有用建议。
更新
我在工作进程中发送函数时出错
似乎我发现了我的错误,正确的版本函数无效:
void respond(int fd)
{
char mesg[99999], *reqline[3], data_to_send[BYTES], path[99999];
int rcvd, fileDesc, bytes_read;
memset( (void*)mesg, (int)' ', 99999 );
const char *ROOT = "/home/web_server/";
int RecvResult = recv(fd,mesg, 99999, MSG_NOSIGNAL);
//EAGAIN - "there is no data available right now, try again later
if (RecvResult == 0 && errno != EAGAIN){
shutdown(fd,SHUT_RDWR);
close(fd);
std::cout << "error recv" << std::endl;
return;
}else if (RecvResult >0){
printf("%s", mesg);
reqline[0] = strtok (mesg, " tn"); // split on lexemes
if ( strncmp(reqline[0], "GET ", 4)==0 ) // if first 4 character equal
{
reqline[1] = strtok (NULL, " t");
reqline[2] = strtok (NULL, " tn");
std::cout << "reqline 1 " << reqline[1] << std::endl;
std::cout << "reqline 2 " << reqline[2] << std::endl;
if ( strncmp( reqline[2], "HTTP/1.0", 8)!=0
&& strncmp(reqline[2], "HTTP/1.1", 8 ) !=0 )
{
send(fd, "HTTP/1.0 400 Bad Requestn", 25 , MSG_NOSIGNAL);
}
else
{
if ( strncmp(reqline[1], "/ ", 2)==0 )
reqline[1] = "/index.html";
strcpy(path, ROOT);
strcpy(&path[strlen(ROOT)], reqline[1]);
printf("file: %sn", path);
if ( (fileDesc=open(path, O_RDONLY))!=-1 )
{
send(fd, "HTTP/1.0 200 OKnn", 17, MSG_NOSIGNAL);
while ( (bytes_read=read(fileDesc, data_to_send, BYTES))>0 )
{
if (bytes_read != -1)
send (fd, data_to_send, bytes_read, MSG_NOSIGNAL);
}
}
else send(fd, "HTTP/1.0 404 Not Foundn", 23, MSG_NOSIGNAL);
}
shutdown(fd,SHUT_RDWR);
close(fd);
}
}else {
std::cout << "Client disconnected unexpect" << std::endl;
}
}
问题是,我关闭了套接字,然后我尝试从这个套接字读取。
相关文章:
- 是否可以通过C++扩展强制多个python进程共享同一内存
- IPC使用多个管道和分支进程来运行Python程序
- c++多进程编写一个唯一的文件
- 多线程:线程或进程.h - C++
- 在 Windows/C++ 上使用多进程应用程序的高精度定时操作
- 优化吞吐量:多线程与多进程
- 多个线程/进程是否可以在不同步的情况下同时从/写入文件的非重叠区域?
- 进程退出,返回值3221225477访问多维向量
- 多进程 c++(11),链表指针作为全局变量
- 与多线程一起登录多进程应用程序
- 分析多进程系统
- C++如何检查文件是否在使用-多线程多进程系统
- GDB/DDD:使用多进程应用程序 C/C++调试共享库
- 多线程和多进程应用程序的锁定机制之间有什么区别
- 如何计算Linux中多进程应用程序的CPU使用率
- c++ /SQLite -数据库访问与多进程
- 多进程锁机制
- C++多进程共享内存实现
- 同步多进程与FileLock()读/写同一文件c++ win32
- OpenSSL pkcs# 11签名多进程