网络设计网站建设类网站模板,自己可以建网站吗,好学校平台网站模板下载,专建网站今天给大家说说前几天完成的一个模拟的网络计算机吧#xff0c;虽然计算机的模拟实现的原理很简单#xff0c;但是如果要想写乘网络的#xff0c;个人认为是不简单的。基本上算是包涵了套接字编程的三分之一的知识点#xff0c;此处的套接字编程指的是在理解TCP/IP五层协议…今天给大家说说前几天完成的一个模拟的网络计算机吧虽然计算机的模拟实现的原理很简单但是如果要想写乘网络的个人认为是不简单的。基本上算是包涵了套接字编程的三分之一的知识点此处的套接字编程指的是在理解TCP/IP五层协议的基础上如果不算理解这些协议的话那么我感觉实现这个应该是包含了多半的套接字编程。下面就让我们看看代码吧
#pragma once
#include pthread.h
#include iostream
#include queue
#include string
#include semaphore.h
#include deal.hpp
#define PTHREAD_NUM 6
#define TASKNUM 5template class T
class pthreadPool;
template class T
struct data
{std::string _name;pthreadPoolT *_str;data(pthreadPoolT *str) : _str(str){}
};
template class T
class pthreadPool
{
public:friend dataT;static pthreadPoolT *get(){return _str;}void run(const T x, int sock){_task x;_sock sock;}void start(){for (size_t i 0; i PTHREAD_NUM; i){dataT *p new dataT(this);if (i % 2 0)p-_name product;elsep-_name consumer;pthread_create(tid i, nullptr, enter, p);}std::cout wancheng std::endl;}~pthreadPool(){pthread_mutex_destroy(_pmtx);pthread_mutex_destroy(_cmtx);sem_destroy(_p);sem_destroy(_c);for (size_t i 0; i PTHREAD_NUM; i)pthread_join(tid[i], nullptr);}private:int _sock 0;T _task T();pthread_t tid[PTHREAD_NUM];pthread_mutex_t _pmtx;pthread_mutex_t _cmtx;sem_t _p;sem_t _c;int _pp 0;int _cc 0;std::vectorT _v;static pthreadPoolT *_str;pthreadPool(){_v.resize(TASKNUM);sem_init(_p, 0, TASKNUM);sem_init(_c, 0, 0);pthread_mutex_init(_cmtx, nullptr);pthread_mutex_init(_pmtx, nullptr);}void product(const T x){// 生产数据sem_wait(_p);pthread_mutex_lock(_pmtx);_v[_pp] x;_pp _pp % TASKNUM;_task T();pthread_mutex_unlock(_pmtx);sem_post(_c);}void consumer(){T x;// 消费数据sem_wait(_c);pthread_mutex_lock(_cmtx);x _v[_cc];_cc _cc % TASKNUM;pthread_mutex_unlock(_cmtx);sem_post(_p);// 处理数据deal(x, _sock);}static void *enter(void *args){dataT *p reinterpret_castdataT *(args);while (true){if (strcmp(p-_name.c_str(), product) 0 p-_str-_task ! T())p-_str-product(p-_str-_task);else if (strcmp(p-_name.c_str(), consumer) 0)p-_str-consumer();//std::cout xiuxi std::endl;continue;}delete p;return nullptr;}
};
template class T
pthreadPoolT *pthreadPoolT::_str new pthreadPoolT();
#pragma once
#include iostream
#include string
#include cstring
#include unistd.h
#include sys/types.h
#include sys/socket.h
#include netinet/in.h
#include arpa/inet.h
void deal(std::string data, int sock)
{// 反序列化std::string respon;int x 0;int y 0;char op \0;int lpos data.find( );int rpos data.rfind( );// std::coutlpos rposstd::endl;if (lpos ! std::string::npos rpos ! std::string::npos){x atoi(data.substr(lpos - 1).c_str());op *data.substr(lpos 1, rpos - 1).c_str();y atoi(data.substr(rpos 1).c_str());// std::coutx y opstd::endl;}else{if (data std::string())return;else{std::cout 式子格式错误 std::endl;exit(4);}}// 处理switch (op){case :respon std::to_string(x y);break;case -:respon std::to_string(x - y);break;case *:respon std::to_string(x * y);break;case /:respon std::to_string(x / y);break;default:std::cout 计算格式错误 std::endl;break;}// 关闭链接send(sock, respon.c_str(), respon.size(), 0);close(sock);
}
#include iostream
#include unistd.h
#include sys/types.h
#include sys/socket.h
#include netinet/in.h
#include signal.h
#include pthread.h
#include arpa/inet.h
#include cstring
#include string
#include pthreadPool.hpp
#define NUMSIZE 1024
const int listen_queue_flag 20;
void func(pthreadPoolstd::string pt, int sock)
{char buffer[NUMSIZE];memset(buffer, 0, NUMSIZE);ssize_t s recv(sock, buffer, NUMSIZE, 0);std::cout buffer std::endl;if (s 0){std::string bufe buffer;pt.run(bufe, sock);}
}
// 主函数
int main(int argc, char *argv[])
{signal(SIGPIPE, SIG_IGN);signal(SIGCHLD, SIG_IGN);if (argc ! 2){std::cout 格式错误 std::endl;exit(1);}// 创建套接字int listensock socket(AF_INET, SOCK_STREAM, 0);if (listensock 0){std::cout socket enrro std::endl;exit(1);}// 开始绑定sockaddr_in local;local.sin_addr.s_addr inet_addr(0.0.0.0);local.sin_family AF_INET;local.sin_port htons(atoi(argv[1]));int ret bind(listensock, (sockaddr *)local, sizeof(local));if (ret 0){std::cout bind enrro std::endl;exit(2);}// 监听int listens listen(listensock, listen_queue_flag);if (listens 0){std::cout listen enrro std::endl;exit(3);}// 建立线程池pthreadPoolstd::string *pstr pthreadPoolstd::string::get();pstr-start();// 建立链接while (true){sockaddr_in client;socklen_t len sizeof(client);int sersock accept(listensock, (sockaddr *)client, len);if (sersock 0){std::cout accept enrro std::endl;continue;}func(*pstr, sersock);}return 0;
}
#include iostream
#include sys/types.h
#include sys/socket.h
#include netinet/in.h
#include arpa/inet.h
#include cstring
#include unistd.h
#define NUM 10
int main(int argc, char *argv[])
{if (argc ! 3){std::cout 格式错误 std::endl;exit(1);}int sock socket(AF_INET, SOCK_STREAM, 0);if (sock 0){std::cout socket enrro std::endl;exit(2);}sockaddr_in serve;memset(serve, 0, sizeof(serve));serve.sin_addr.s_addr inet_addr(argv[1]);serve.sin_family AF_INET;serve.sin_port htons(atoi(argv[2]));int ret connect(sock, (sockaddr *)serve, sizeof(serve));// std::coutretstd::endl;if (ret 0){// 连接成功std::string buffer;getline(std::cin, buffer);// std::coutbufferstd::endl;send(sock, buffer.c_str(), buffer.size(), 0);char bufe[NUM];memset(bufe, 0, NUM);ssize_t s recv(sock, bufe, NUM, 0);std::cout bufe std::endl;close(sock);}else{std::cout连接错误std::endl;exit(5);}return 0;
}
以上就是代码代码量不大但是主要是考虑的比较多。我又加了个线程池。如果是单生产者还好但是我写成了多生产者和多消费者这里就有好多问题困扰了我很久这个计算机我大概写了有半个月左右吧难就难在了这个线程池的地方。下面先说说他的问题吧。
1.
首先就是我在服务端创建线程池的时候迷糊了很久刚开始我是在服务端创建了一个新线程让这个新线程去调用线程池的函数但是后来我发现不行因为当时我是把关闭套接字的文件写到了服务端这就导致一个问题线程创建完成之后线程池中的线程回去执行任务但是服务端的线程出来之后就直接关闭文件了导致无法发送。所以我就想了很长时间最后把这个操作写到了处理函数的那里这样就避免了连接错误以及服务端创建线程的问题减少了消耗。
2.
其次而来的问题就是因为这个线程池是多生产者多消费者的所以我就想的是提高一点效率携程了可以并发执行的模型但是问题又来了他们怎么插入任务要知道的是服务端可不是生产者的角色他只是负责把读取的人插到线程池这就引发了一个问题怎么插所以我想了想便在县城的私有成员变量中写了一个任务和套接字的文件描述符。但是这样还有问题不知道大家注意到了我的线程池中的插入我没有用引用这样会造成拷贝构造但是这样可以大大降低错误发生概率是的解决不了(我没有想到解决方法)这样写的目的是在一个客户端访问时我先运行run函数然后我的生产者会插入任务但是如果刚好在插入任务的之前又有一个客户端访问时此时的线程中的任务变量就会改变。所以我没有用引用这样的话就可以在一定概率上解决这个问题但是还是彻底解决不了。
3.
其次就是我写的是短连接这个可以保证多人同时访问服务端不崩。 如果上面的实现用单生产者多消费者的话就可以解决此方法如果用小伙伴知道解决的方法希望告知谢谢。