申请微信支付公司网站网站购物车实现
- 作者: 五速梦信息网
- 时间: 2026年04月20日 09:22
当前位置: 首页 > news >正文
申请微信支付公司网站,网站购物车实现,济南高新区 网站建设公司,网络营销课程个人感悟目录 前言#xff1a; 1、InitServer类的实现 1.1. 创建流式套接字 1.2. bind 绑定一个固定的网络地址和端口号 1.3.listen监听机制 1.4.完整代码
- 循环接收接口与服务接口 2.1.accept函数讲解 讲个商场拉客的故事方便我们理解#xff1a; 2.2.服务接口实现 3.服…目录 前言 1、InitServer类的实现 1.1. 创建流式套接字 1.2. bind 绑定一个固定的网络地址和端口号 1.3.listen监听机制 1.4.完整代码 2. 循环接收接口与服务接口 2.1.accept函数讲解 讲个商场拉客的故事方便我们理解 2.2.服务接口实现 3.服务端和客户端的实现 3.1.服务端 3.2.客户端 connect函数讲解 4.多版本测试运行 4.1.单进程处理 4.2.多进程处理 测试结果 4.3.多线程处理 代码编辑 前言 我们上一篇文章讲解了利用udp协议实现一个简单的echo_server程序将客户端的数据在服务端打印出来UDP协议。今天我们来讲解利用TCP协议实现的一个简单的echo_server程序认识并熟悉各个接口的功能以及如何使用 1、InitServer类的实现 1.1. 创建流式套接字 socket函数讲解 socket()打开一个网络通讯端口,如果成功的话,就像 open()一样返回一个文件描述符;应用程序可以像读写文件一样用 read/write 在网络上收发数据;如果 socket()调用出错则返回-1;对于 IPv4, family 参数指定为 AF_INET;对于 TCP 协议,type 参数指定为 SOCK_STREAM, 表示面向流的传输协议protocol 参数的介绍从略,指定为 0 即可。 该部分与udp唯一的区别就是type参数的不同因为对于TCP协议是面向流的传输协议所以参数指定为SOCK_STREAM。 代码 1.2. bind 绑定一个固定的网络地址和端口号 服务器程序所监听的网络地址和端口号通常是固定不变的,客户端程序得知服务器程序的地址和端口号后就可以向服务器发起连接; 服务器需要调用 bind 绑定一个固定的网络地址和端口号;bind()成功返回 0,失败返回-1。bind()的作用是将参数 sockfd 和 myaddr 绑定在一起, 使 sockfd 这个用于网络通讯的文件描述符监听 myaddr 所描述的地址和端口号;struct sockaddr *是一个通用指针类型,myaddr 参数实际上可以接受多种协议的 sockaddr 结构体,而它们的长度各不相同,所以需要第三个参数 addrlen指定结构体的长度; 注意这部分代码与udp是一模一样的。 代码 1.3.listen监听机制 listen函数讲解 listen()声明 sockfd 处于监听状态, 并且最多允许有 backlog 个客户端处于连接等待状态, 如果接收到更多的连接请求就忽略, 这里设置不会太大(一般是 5)listen()成功返回 0,失败返回-1; tcp是面向连接的所以通信之前必须先建立连接。服务器是被连接的。tcpserver 启动未来首先要一直等待客户的连接到来所以需要listen函数进行监听。 代码 1.4.完整代码 void InitServer(){// 1. 创建流式套接字_listensock ::socket(AF_INET, SOCK_STREAM, 0);if (_listensock 0){LOG(FATAL, socket error);exit(SOCKET_ERROR);}LOG(DEBUG, socket create success, sockfd is : %d\n, _listensock);// 2. bindstruct sockaddr_in local;memset(local, 0, sizeof(local));local.sin_family AF_INET;local.sin_port htons(_port);local.sin_addr.s_addr INADDR_ANY;int n ::bind(_listensock, (struct sockaddr *)local, sizeof(local));if (n 0){LOG(FATAL, bind error);exit(BIND_ERROR);}LOG(DEBUG, bind success, sockfd is : %d\n, _listensock);// 3. tcp是面向连接的所以通信之前必须先建立连接。服务器是被连接的// tcpserver 启动未来首先要一直等待客户的连接到来n ::listen(_listensock, gbacklog);if (n 0){LOG(FATAL, listen error);exit(LISTEN_ERROR);}LOG(DEBUG, listen success, sockfd is : %d\n, _listensock);} 2. 循环接收接口与服务接口 Loop循环循环接收接口需要 不断从套接字文件中accept获取连接流与客户端信息获取成功后就可以进行服务了服务就是从流中读取数据然后处理之后再写回流中!!!使用的接口是read与write文件流中我们对他们很熟悉 2.1.accept函数讲解 三次握手完成后, 服务器调用 accept()接受连接;如果服务器调用 accept()时还没有客户端的连接请求,就阻塞等待直到有客户端连接上来;addr 是一个传出参数,accept()返回时传出客户端的地址和端口号;如果给 addr 参数传 NULL,表示不关心客户端的地址; accept返回的套接字和传入的参数套接字到底有什么关系 传入的套接字这个参数不是真正参与通信的只是用来建立连接的。我们真正用来与客户端通信的是返回的套接字 讲个商场拉客的故事方便我们理解 就比如我们在商场逛街很多门面前面有拉客的拉客的人在马路上拉客然后接到客人之后会从店里再喊一个服务员用来服务新拉过来的客人。因此拉客的人就是我们的参数而返回值的套接字才是真正服务我们的也就是说如果有多个客人就会有很多个返回值的套接字分别用来服务。 部分代码 2.2.服务接口实现 服务就是从流中读取数据然后处理之后再写回流中。使用的接口是read与write。 void Service(int sockfd, InetAddr client){LOG(DEBUG, get a new link, info %s:%d, fd : %d\n, client.Ip().c_str(), client.Port(), sockfd);std::string clientaddr [ client.Ip() : std::to_string(client.Port()) ]# ;while (true){char inbuffer[1024];ssize_t n read(sockfd, inbuffer, sizeof(inbuffer) - 1);if (n 0){inbuffer[n] 0;std::cout clientaddr inbuffer std::endl;std::string echo_string [server echo]# ;echo_string inbuffer;write(sockfd, echo_string.c_str(), echo_string.size());}else if (n 0){// client 退出关闭连接了LOG(INFO, %s quit\n, clientaddr.c_str());break;}else{LOG(ERROR, read error\n, clientaddr.c_str());break;}}std::cout server开始退出 std::endl;shutdown(sockfd, SHUT_RD);std::cout shut _ rd std::endl;sleep(10);//shutdown(sockfd, SHUT_WR);//std::cout shut _ wr std::endl;//::close(sockfd); // 文件描述符泄漏} 3.服务端和客户端的实现 3.1.服务端 服务端简单的创建一个服务器类然后进行初始化和loop就可以了。 代码 #include TcpServer.hpp #include memoryvoid Usage(std::string proc) {std::cout Usage:\n\t proc local_port\n std::endl; }// ./tcpserver port int main(int argc, char argv[]) {if(argc ! 2){Usage(argv[0]);return 1;}EnableScreen();uint16_t port std::stoi(argv[1]);std::unique_ptrTcpServer tsvr std::make_uniqueTcpServer(port);tsvr-InitServer();tsvr-Loop();return 0; } 3.2.客户端 首先根据传入的参数进行初始化服务器IP地址和端口号然后创建套接字文件 并进行connect连接绑定bind,客户端回被动绑定一个端口号。绑定成功之后就可以通过sockfd进行写入与读取了。 connect函数讲解 客户端需要调用 connect()连接服务器;connect 和 bind 的参数形式一致, 区别在于 bind 的参数是自己的地址, 而connect 的参数是对方的地址;connect()成功返回 0,出错返回-1; 代码 #include iostream #include string #include sys/types.h / See NOTES */ #include sys/socket.h #include netinet/in.h #include arpa/inet.h #include unistd.h #include cstringvoid Usage(std::string proc) {std::cout Usage:\n\t proc serverip serverport\n std::endl; }// ./tcp_client serverip serverport int main(int argc, char *argv[]) {if (argc ! 3){Usage(argv[0]);exit(1);}std::string serverip argv[1];uint16_t serverport std::stoi(argv[2]);int sockfd ::socket(AF_INET, SOCK_STREAM, 0);if (sockfd 0){std::cerr socket error std::endl;exit(2);}// tcp client 要bind不要显示的bind.struct sockaddr_in server;// 构建目标主机的socket信息memset(server, 0, sizeof(server));server.sin_family AF_INET;server.sin_port htons(serverport);server.sin_addr.s_addr inet_addr(serverip.c_str());int n connect(sockfd, (struct sockaddr *)server, sizeof(server));if (n 0){std::cerr connect error std::endl;exit(3);}while(true){std::cout Please Enter# ;std::string outstring;std::getline(std::cin, outstring);ssize_t s send(sockfd, outstring.c_str(), outstring.size(), 0); //writeif(s 0){char inbuffer[1024];ssize_t m recv(sockfd, inbuffer, sizeof(inbuffer)-1, 0);if(m 0){inbuffer[m] 0;std::cout inbuffer std::endl;}else{break;}}else{break;}}shutdown(sockfd, SHUT_WR);//::close(sockfd);return 0; } 4.多版本测试运行 4.1.单进程处理 一次只能处理一个请求显然这个版本是很废的根本不满足用户需求直接跳过 测试结果 4.2.多进程处理 子进程会继承父进程的文件描述符表所以子进程一定会看到父进程之前创建的sockfd父子进程的文件描述符表是独立的子进程会拷贝父进程的那一份线程才会共享 对于子进程关心sockfd 不关心listensock所以对于子进程需要关闭listensock对于父进程关心listensock不关心sockfd所以对于父进程需要关闭sockfd 为什么父进程要关闭sockfd不然一直创建会导致sockfd一直减少浪费资源 子进程还会创建子进程就是孙子进程我们不进行任何处理那么这个孙子进程就变成了孤儿进程系统自己领养进行运行而父进程仍在源源不断的创建新的子进程那么这个版本服务器就可以并发处理了 代码 // Version 1: 采用多进程pid_t id fork();if (id 0){// child : 关心sockfd 不关心listensock::close(_listensock); // 建议if(fork() 0) exit(0); Service(sockfd, InetAddr(peer)); //孙子进程 – 孤儿进程 — 系统领养exit(0);}// father 关心listensock不关心sockfd::close(sockfd);waitpid(id, nullptr, 0); 测试结果 测试成功但是我们知道切换进程时CPU会切换上下文和热点数据。在并发场景下多进程的不断切换会消耗大量的性能 而作为轻量级进程的线程就可以避免这样的问题 4.3.多线程处理 我们采用线程分离的方法来实现并发处理 多线程禁止关闭文件描述符因为多线程是共享文件描述符表的如果直接将sockfd关掉了那么先创建的线程可能无法通过文件描述符来读取数据。 在服务器编程中为了处理大量的客户端请求可以采用多线程技术来提高服务器的并发性能。在这种情况下线程分离可以确保每个子线程在结束后自动释放资源从而避免资源泄露提高服务器的稳定性和性能。 代码 测试结果非常nice
- 上一篇: 申请网站建设费用的请示公共资源交易网
- 下一篇: 申请一个网站需要多少钱装修公司资质
相关文章
-
申请网站建设费用的请示公共资源交易网
申请网站建设费用的请示公共资源交易网
- 技术栈
- 2026年04月20日
-
申请完域名如何建网站专门查企业信息的网站
申请完域名如何建网站专门查企业信息的网站
- 技术栈
- 2026年04月20日
-
申请完域名如何建网站南宁建站模板源码
申请完域名如何建网站南宁建站模板源码
- 技术栈
- 2026年04月20日
-
申请一个网站需要多少钱装修公司资质
申请一个网站需要多少钱装修公司资质
- 技术栈
- 2026年04月20日
-
申请域名 建设网站建站的注意事项
申请域名 建设网站建站的注意事项
- 技术栈
- 2026年04月20日
-
申请域名后 怎么把网站部署上去做网站开发的有哪些公司好
申请域名后 怎么把网站部署上去做网站开发的有哪些公司好
- 技术栈
- 2026年04月20日
