怒江州建设局网站企业备案网站,怎样做服装网站,推荐西安优秀的高端网站建设公司,网站直播怎样做1️⃣ 在linux下#xff0c;通过套接字实现服务器和客户端的通信。 2️⃣ 实现单线程、多线程通信。或者实现线程池来通信。 3️⃣ 优化通信#xff0c;增加守护进程。
有情提醒#xff0c;类里面默认的函数是内联。内联函数在调用的地方展开#xff0c;没有函数地址…1️⃣ 在linux下通过套接字实现服务器和客户端的通信。 2️⃣ 实现单线程、多线程通信。或者实现线程池来通信。 3️⃣ 优化通信增加守护进程。
有情提醒类里面默认的函数是内联。内联函数在调用的地方展开没有函数地址无法保持和传递。
一 、
1.1实现TCP服务器
创建socket文件描述符(TCP/UDP,客户端服务端)
int socket(int domain, int type, int protocol);
绑定端口号(TCP/UDP,服务器
int bind(int socket, const struct sockaddr *address,socklen_t address_len);
开始监听socket (TCP, 服务器)
int listen(int socket, int backlog);
// 接收请求 (TCP, 服务器)
int accept(int socket, struct sockaddr* address,socklen_t* address_len);
// 建立连接 (TCP, 客户端
int connect(int sockfd, const struct sockaddr*addr,socklen_t addrlen);void init(){// 1.创建套接字// 1.1 协议族 1.2 SOCK_STREAM是一个有序、可靠、面向连接 的双向字节流 1.3建立一个流式套接字listenSock_ socket(PF_INET, SOCK_STREAM, 0);if (listenSock_ 0){logMessage(FATAL, socket: %s, strerror(errno));exit(SOCKET_ERR);}logMessage(DEBUG, socket: %s,%d, strerror(errno), listenSock_);// 2.bind绑定// 2.1填充服务器信息// sockaddr_in是系统封装的一个结构体// 具体包含了成员变量sin_family、sin_addr、sin_zerostruct sockaddr_in local; // 用户栈memset(local, 0, sizeof local);local.sin_family PF_INET;local.sin_port htons(port_);// 绑定INADDR_ANY管理一个套接字不管数据是从哪个网卡过来的只要是绑定的端口号过来的数据都可以接收到。// 将一个网络字节序的IP地址也就是结构体in_addr类型变量转化为点分十进制的IP地址字符串。ip_.empty() ? (local.sin_addr.s_addr INADDR_ANY) : (inet_aton(ip_.c_str(), local.sin_addr));// 2.2本地socket信息,写入sock_对应的内核区域if (bind(listenSock_, (const struct sockaddr *)local, sizeof local) 0) // 说明绑定错误{logMessage(FATAL, bind :%s, strerror(errno));exit(BIND_ERR);}logMessage(DEBUG, bind :%s,%d, strerror(errno), listenSock_);// 3.监听socketif (listen(listenSock_, 5) 0){logMessage(FATAL, listen :%s, strerror(errno));exit(LISTEN_ERR);}logMessage(DEBUG, listen :%s,%d, strerror(errno), listenSock_);// 4.启动线程池tp_ ThreadPoolTask::getInstance();}void loop(){// 启动线程池tp_-start();logMessage(DEBUG, thread pool start success ,thread number : %d, tp_-ThreadNum());// signal(SIGCHLD,SIG_IGN);//基类忽略子类信号while (true){struct sockaddr_in peer;socklen_t len sizeof(peer);// 4.获取连接,accept的返回值是一个新的socketint serviceSock accept(listenSock_, (struct sockaddr *)peer, len);if (serviceSock 0){logMessage(WARINING, accept :%s[%d], strerror(errno), serviceSock);continue;}// 4.1获取客户端基本信息uint16_t peerPort ntohs(peer.sin_port); // 将一个16位数由网络字节顺序转换为主机字节顺序std::string peerIp inet_ntoa(peer.sin_addr);logMessage(DEBUG, accept :%s | %s[%d],socket fd: %d, strerror(errno), peerIp.c_str(), peerPort, serviceSock);// 5.3 版本 --线程池版本// 5.3.1 构建任务// Task t(serviceSock, peerIp, peerPort, std::bind(ServerTcp::transService, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));// tp_-push(t);//将获取的任务给线程池,目前线程池只有5个线程// 5.3.2// 直接使用回调函数Task t(serviceSock, peerIp, peerPort, execCommand);// Task::callback_t call execCommand;tp_-push(t);// popen传入命令字符串,让它能以文件的方式读到命令接口}}#include sys/types.h
#include sys/socket.h
int accept(int sockfd,struct sockaddr *addr,socklen_t *addrlen);
sockfd,利用系统调用socket()建立的套接字描述符通过bind()绑定到一个本地地址(一般为服务器的套接字)并且通过listen()一直在监听连接
addr,指向struct sockaddr的指针该结构用通讯层服务器对等套接字的地址(一般为客户端地址)填写返回地址addr的确切格式由套接字的地址类别(比如TCP或UDP)决定若addr为NULL没有有效地址填写这种情况下addrlen也不使用应该置为NULL
addrlen,一个值结果参数调用函数必须初始化为包含addr所指向结构大小的数值函数返回时包含对等地址(一般为服务器地址)的实际数值上边绑定的时候需要将16位主机字节序转16位网络字节序。还有设置cockaddr_in的结构体里面有域、协议家族该结构体是系统封装的。就是处理网络字节和主机字节的相互转换。获取连接的时候需要重新将网络字节序转化为主机字节序。accept返回的是一个新的socket 1.2实现UDP客户端 创建socket套接字 connect向服务器发起链接请求 int main(int argc,char *argv[])
{if(argc!3){Usage(argv[0]);exit(USAGE_ERR);}// ./clientTcp serverIp serverPort//默认argc为1argv[0]为程序名称。如果输入一个参数则argc为2std::string serverIpargv[1];uint16_t serverPortatoi(argv[2]);//1.创建soketint socksocket(AF_INET,SOCK_STREAM,0);if(sock0){std::cerrsocket:strerror(errno)std::endl;exit(SOCKET_ERR);}//2.CONNECT向服务器发起链接请求//2.1先填充需要连接的远端主机的基本信息struct sockaddr_in server;memset(server,0,sizeof(server));server.sin_familyAF_INET;server.sin_porthtons(serverPort);//将一个16位主机字节顺序转换成网络字节顺序inet_aton(serverIp.c_str(),server.sin_addr);//将一个网络字节序的IP地址也就是结构体in_addr类型变量转化为点分十进制的IP地址字符串。//2.2发起请求connect自动绑定bindif(connect(sock,(const struct sockaddr *)server,sizeof(server))!0){std::cerrconnect:strerror(errno)std::endl;exit(CONN_ERR);}std::coutinof : connect success: sockstd::endl;std::string message;while (!quit){message.clear();std::cout请输入你的消息;std::getline(std::cin,message);if(strcasecmp(message.c_str(),quit)0){quittrue;}size_t swrite(sock,message.c_str(),message.size());if(s0){message.resize(1024);ssize_t sread(sock,(char *)(message.c_str()),1024);if(s0)message[s]0;std::coutServer Echomessagestd::endl;}else if(s0){break;}}close(sock);return 0;
}以上代码主要是创建套接字获取远端信息端口和ip将主机字节顺序转换为网络字节顺序。使用connect请求连接。
#include sys/types.h
#include sys/socket.h
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);参数
第一个参数int sockdfsocket文件描述符
第二个参数 const struct sockaddr *addr传入参数指定服务器端地址信息含IP地址和端口号
第三个参数socklen_t addrlen传入参数,传入sizeof(addr)大小
返回值成功 0失败-1设置errnoconnect函数返回后并不进行数据交换。而是要等服务器端 accept 之后才能进行数据交换read、write。客户端端需要调用connect()连接服务器connect和bind的参数形式一致区别在于bind的参数是自己的地址而connect的参数是对方的地址。
二、
我们这边要注意既然是实现服务器与客户端互通。我们提供服务就需要考虑让多人连接单人连接等问题。 以下我们实现单线程和多线程版本。 提供服务 void transService(int sock,const std::string clientIp,uint16_t clientPort) { assert(sock0); assert(!clientIp.empty()); assert(clientPort1024); char inbuffer[BUFFER_SIZE];while (true){size_t sread(sock,inbuffer,sizeof(inbuffer)-1);if(s0){inbuffer[s]\0;if(strcasecmp(inbuffer,quit)0){logMessage(DEBUG,client quit -- %s[%d],clientIp.c_str(),clientPort);break;}logMessage(DEBUG,trans before: %s[%d]%s,clientIp.c_str(),clientPort,inbuffer);//大小写转换for(int i 0;is;i){if(isalpha(inbuffer[i])islower(inbuffer[i])){inbuffer[i]toupper(inbuffer[i]);}}logMessage(DEBUG,trans after : %s[%d] %s,clientIp.c_str(),clientPort,inbuffer);write(sock,inbuffer,strlen(inbuffer));}else if(s0){logMessage(DEBUG,client quit -- %s[%d],clientIp.c_str(),clientPort);break;}else{logMessage(DEBUG,%s[%d] - read:%s,clientIp.c_str(),clientPort,strerror(errno));break;}}close(sock);logMessage(DEBUG,server close %d done,sock);}单线程版本
直接传套接字、ip、端口号 cpptransService(serviceSock,peerIp,peerPort);多线程版本 //5.1 多线程版本pid_t idfork();if(id0){ //基类进程close(listenSock_);//又进行了一次fork让if(fork()0) exit(0);//子类进程 基类退出--子类还在被系统拿到--回收问题就交给系统回收transService(serviceSock,peerIp,peerPort);exit(0);//子进程退出后会进入僵尸状态}//基类退出close(serviceSock);//获取基类退出后的退出码pid_t retwaitpid(id,nullptr,0);assert(ret0);(void)ret;//多线程会共享文件描述符表 ThreadData tdnew ThreadData(peerPort,peerIp,serviceSock,this); pthread_t tid; pthread_create(tid,nullptr,threadRoutine,(void)td); pthread_detach的使用让每个线程结束后自动释放自己所用的资源。 int serviceSockaccept(listenSock_,(struct sockaddr*)peer,len);每个用户连接后需要执行5步。 ThreadData *tdnew ThreadData(peerPort,peerIp,serviceSock,this);这步是为了将主线程把链接信息封装好然后创建子线程让子线程去处理这份数据然后等待下一个链接。 pthread_create就是完成第一行的创建子进程是执行子进程对应的任务。
线程池版本
pthread_mutex_init的使用是为了解决在多线程访问共享资源时多个线程同时对共享资源操作产生的冲突而提出的一种解决方法在执行时哪个线程持有互斥锁,并对共享资源进行加锁后才能对共享资源进行操作此时其它线程不能对共享资源进行操作。 我们先启动线程池 tp_ ThreadPoolTask::getInstance();为每个线程池进行加锁然后启动线程池 tp_-start(); 来了任务就将任务放至任务队列里面如果没有任务就等待。如果有任务就拿任务并且把任务队列的首部弹出该任务。返回任务。 Task t(serviceSock, peerIp, peerPort, execCommand);tp_-push(t);调用程序执和被调用函数同时在执行。当被调函数执行完毕后被调函数会反过来调用某个事先指定函数以通知调用程序函数调用结束。这个过程称为回调(Callback)。
void execCommand(int sock, const std::string clientIp, uint16_t clientPort)
{assert(sock 0);assert(!clientIp.empty());assert(clientPort 1024);char command[BUFFER_SIZE];while (true){size_t s read(sock, command, sizeof(command) - 1);if (s 0){command[s] \0;// 这个用户执行command命令logMessage(DEBUG, [%s:%d] exec [%s] ..done, clientIp.c_str(), clientPort, command);// 考虑安全std::string safe command;if ((std::string::npos ! safe.find(rm)) || (std::string::npos ! safe.find(unlink))){break;}FILE *fp popen(command, r);if (fp nullptr){logMessage(WARINING, exec %s failed,beacuse: %s, command, strerror(errno));break;}// 遍历目录char line[1024];while (fgets(line, sizeof(line) - 1, fp) ! nullptr){write(sock, line, strlen(line));}// //本来要写入dile里但现在写入网络。// dup2(sock,fp-_fileno);// fflush(fp);pclose(fp);logMessage(DEBUG, [%s:%d] exec [%s]...done, clientIp.c_str(), clientPort, command);}else if (s 0){logMessage(DEBUG, client quit -- %s[%d], clientIp.c_str(), clientPort);break;}else{logMessage(DEBUG, %s[%d] - read:%s, clientIp.c_str(), clientPort, strerror(errno));break;}}close(sock);logMessage(DEBUG, server close %d done, sock);
}对于线程池我的理解还是不行。希望能多多与大家一块交流。 文章转载自: http://www.morning.tsynj.cn.gov.cn.tsynj.cn http://www.morning.mdnnz.cn.gov.cn.mdnnz.cn http://www.morning.crsnb.cn.gov.cn.crsnb.cn http://www.morning.zhqfn.cn.gov.cn.zhqfn.cn http://www.morning.ntqnt.cn.gov.cn.ntqnt.cn http://www.morning.kvzvoew.cn.gov.cn.kvzvoew.cn http://www.morning.sjjtz.cn.gov.cn.sjjtz.cn http://www.morning.rlpmy.cn.gov.cn.rlpmy.cn http://www.morning.hkchp.cn.gov.cn.hkchp.cn http://www.morning.lzdbb.cn.gov.cn.lzdbb.cn http://www.morning.xjpnq.cn.gov.cn.xjpnq.cn http://www.morning.mmhyx.cn.gov.cn.mmhyx.cn http://www.morning.plgbh.cn.gov.cn.plgbh.cn http://www.morning.wqhlj.cn.gov.cn.wqhlj.cn http://www.morning.znnsk.cn.gov.cn.znnsk.cn http://www.morning.fkdts.cn.gov.cn.fkdts.cn http://www.morning.txlnd.cn.gov.cn.txlnd.cn http://www.morning.rkqqf.cn.gov.cn.rkqqf.cn http://www.morning.ywrt.cn.gov.cn.ywrt.cn http://www.morning.xlxmy.cn.gov.cn.xlxmy.cn http://www.morning.qzpqp.cn.gov.cn.qzpqp.cn http://www.morning.rhkmn.cn.gov.cn.rhkmn.cn http://www.morning.nyjgm.cn.gov.cn.nyjgm.cn http://www.morning.lznfl.cn.gov.cn.lznfl.cn http://www.morning.gpmrj.cn.gov.cn.gpmrj.cn http://www.morning.yxyyp.cn.gov.cn.yxyyp.cn http://www.morning.rtryr.cn.gov.cn.rtryr.cn http://www.morning.wjlkz.cn.gov.cn.wjlkz.cn http://www.morning.cbpkr.cn.gov.cn.cbpkr.cn http://www.morning.nwljj.cn.gov.cn.nwljj.cn http://www.morning.pctql.cn.gov.cn.pctql.cn http://www.morning.mtbsd.cn.gov.cn.mtbsd.cn http://www.morning.qrwdg.cn.gov.cn.qrwdg.cn http://www.morning.drnfc.cn.gov.cn.drnfc.cn http://www.morning.owenzhi.com.gov.cn.owenzhi.com http://www.morning.rbkml.cn.gov.cn.rbkml.cn http://www.morning.nwllb.cn.gov.cn.nwllb.cn http://www.morning.mrgby.cn.gov.cn.mrgby.cn http://www.morning.dbcw.cn.gov.cn.dbcw.cn http://www.morning.dgknl.cn.gov.cn.dgknl.cn http://www.morning.dytqf.cn.gov.cn.dytqf.cn http://www.morning.tyjp.cn.gov.cn.tyjp.cn http://www.morning.zqdhr.cn.gov.cn.zqdhr.cn http://www.morning.zxznh.cn.gov.cn.zxznh.cn http://www.morning.tgxrm.cn.gov.cn.tgxrm.cn http://www.morning.wqgr.cn.gov.cn.wqgr.cn http://www.morning.tqsmc.cn.gov.cn.tqsmc.cn http://www.morning.bncrx.cn.gov.cn.bncrx.cn http://www.morning.sfnjr.cn.gov.cn.sfnjr.cn http://www.morning.lxhny.cn.gov.cn.lxhny.cn http://www.morning.lfjmp.cn.gov.cn.lfjmp.cn http://www.morning.bgxgq.cn.gov.cn.bgxgq.cn http://www.morning.fdsbs.cn.gov.cn.fdsbs.cn http://www.morning.gczzm.cn.gov.cn.gczzm.cn http://www.morning.xjmyq.com.gov.cn.xjmyq.com http://www.morning.cwrnr.cn.gov.cn.cwrnr.cn http://www.morning.ghxtk.cn.gov.cn.ghxtk.cn http://www.morning.llqch.cn.gov.cn.llqch.cn http://www.morning.ncwgt.cn.gov.cn.ncwgt.cn http://www.morning.kpygy.cn.gov.cn.kpygy.cn http://www.morning.tfbpz.cn.gov.cn.tfbpz.cn http://www.morning.qytyt.cn.gov.cn.qytyt.cn http://www.morning.bgygx.cn.gov.cn.bgygx.cn http://www.morning.rrrrsr.com.gov.cn.rrrrsr.com http://www.morning.haolipu.com.gov.cn.haolipu.com http://www.morning.mtmph.cn.gov.cn.mtmph.cn http://www.morning.i-bins.com.gov.cn.i-bins.com http://www.morning.fdlyh.cn.gov.cn.fdlyh.cn http://www.morning.rpzth.cn.gov.cn.rpzth.cn http://www.morning.bhwz.cn.gov.cn.bhwz.cn http://www.morning.lnyds.cn.gov.cn.lnyds.cn http://www.morning.lwxsy.cn.gov.cn.lwxsy.cn http://www.morning.qqfcf.cn.gov.cn.qqfcf.cn http://www.morning.qgkcs.cn.gov.cn.qgkcs.cn http://www.morning.fmznd.cn.gov.cn.fmznd.cn http://www.morning.prlgn.cn.gov.cn.prlgn.cn http://www.morning.rcrfz.cn.gov.cn.rcrfz.cn http://www.morning.wjlbb.cn.gov.cn.wjlbb.cn http://www.morning.jbmbj.cn.gov.cn.jbmbj.cn http://www.morning.bpmnz.cn.gov.cn.bpmnz.cn