C++后台开发 网络编程实践一
来源:互联网 发布:java nexttoken 编辑:程序博客网 时间:2024/06/14 14:14
TTCP(test TCP): classic TCP performance testing tool
1. What performance do we care? 1. Bandwith MB/s 2. Throughput, messages/s, queries/s(QPS), transactions/s (TPS) 3. Latency, millisecond, percentiles 4. Utilization, percent, payload vs. carrier, goodput vs. theory BW 5. Overhead, eg. CPU usage, for compression and /or encryption2. Why do we re-implement TTCP? It uses all basic Sockets APIs: socket, listen, bind, accept, connect, read/recv, write/send, shutdown, close, etc. The protocol is binary, not just byte stream, so it's better than the classic echo example Typical behaviors, meaningful result, instead of packet/s Service as benchmark for programming language as well, by comparing CPU usage Not concurrent, at least in the very basic form3. The Protocol
4. The Code
5. 这个例子用到了muduo库的Timestamp.h来计算时间,需要编译一下muduo库。具体方法:
6. 实例代码:
//main.cc#include "commandLineParser.h"#include "clientAndServer.h"#include <assert.h>int main(int argc, char *argv[]) { Options options; parseCommandLine(argc, argv, &options); if(options.transmit){ transmit(options); } else if(options.receive){ receive(options); } else{ assert(0); } return 0;}
//commandLineParser.h#pragma once#include <string>#include <stdint.h>//需要从命令行获取的信息struct Options{ uint16_t port; int length; int number; bool transmit, receive, nodelay; std::string host; Options() :port(0), length(0), number(0), transmit(false), receive(false), nodelay(false){}};//获取命令行信息bool parseCommandLine(int argc, char *argv[], Options *opt);//从命令中解析出协议族地址struct sockaddr_in resolveAddr(const char * host, uint16_t port);
//commandLineParser.cc#include "commandLineParser.h"#include <boost/program_options.hpp>#include <iostream>#include <netdb.h>#include <stdio.h>using namespace boost::program_options;bool parseCommandLine(int argc, char *argv[], Options *opt){ options_description desc("Allowed options"); desc.add_options() ("help,h", "Help") ("port,p", value<uint16_t>(&opt->port)->default_value(5001), "TCP port") ("length,l", value<int>(&opt->length)->default_value(8192), "Buffer length") ("number,n", value<int>(&opt->number)->default_value(1025), "Number of buffers") ("trans,t", value<std::string>(&opt->host), "Transmit") ("recv,r", "Receive") ("nodelay,D", "set TCP_NODELAY") ; variables_map vm; store(parse_command_line(argc, argv, desc), vm); notify(vm); opt->transmit = vm.count("trans"); opt->receive = vm.count("recv"); opt->nodelay = vm.count("nodelay"); if(vm.count("help")){ std::cout << desc << std::endl; return false; } if(opt->transmit == opt->receive){ printf("either -t or -r must be specified.\n"); return false; } printf("port = %d\n", opt->port); if(opt->transmit){ printf("buffer length = %d\n", opt->length); printf("number of buffers = %d\n", opt->number); } else{ printf("accepting...\n"); } return true;}struct sockaddr_in resolveAddr(const char * host, uint16_t port){ //struct hostent *gethostbyname(const char *hostname); /*struct hostent{ char * h_name; char ** h_aliases; int h_addrtype; int h_length; char ** h_addr_list; #define h_addr h_addr_list[0]*/ struct hostent * getHost = gethostbyname(host); if(!getHost){ printf(hstrerror(h_errno)); exit(1); } assert(getHost->h_addrtype == AF_INET && getHost->h_length == sizeof(uint32_t)); struct sockaddr_in addr; bzero(&addr, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port); //完全无关类型转换 (char *) to (struct in_addr *) addr.sin_addr = *reinterpret_cast<struct in_addr*>(getHost->h_addr); return addr;}
//clientAndServer.h#pragma once#include "commandLineParser.h"#include "protocol.h"#include <stdint.h>#include <assert.h>#include <errno.h>#include <stdio.h>#include <sys/socket.h>#include <sys/types.h>#include <string.h>#include <malloc.h>#include <netinet/in.h>#include <arpa/inet.h>#include <muduo/base/Timestamp.h>// write n byte to sockfdint write_n(int sockfd, const void*buf, int length);// read n byte from sockfdint read_n(int sockfd, void *buf, int length);// accept clientint acceptCli(uint16_t port);// transmit SessionMessage or playload to servervoid transmit(const Options &opt);// receive SessionMessage or playload from clientvoid receive(const Options & opt);
//clientAndServer.cc#include "commandLineParser.h"#include "clientAndServer.h"int acceptCli(uint16_t port){ int listenfd = socket(AF_INET, SOCK_STREAM, 0); assert(listenfd >= 0); int yes = 1; //int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen) if(setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes))){ perror("setsockopt"); exit(1); } struct sockaddr_in servaddr; bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(port); servaddr.sin_addr.s_addr = INADDR_ANY; if(bind(listenfd, reinterpret_cast<struct sockaddr *>(&servaddr), sizeof(servaddr))){ perror("bind"); exit(1); } if(listen(listenfd, 5)){ perror("listen"); exit(1); } int sockfd = accept(listenfd, reinterpret_cast<struct sockaddr *>(NULL), NULL); if(sockfd < 0){ perror("accept"); exit(1); } close(listenfd); return sockfd;}int read_n(int sockfd, void *buf, int length){ int nread = 0; while(nread < length){ ssize_t nr = read(sockfd, static_cast<char*>(buf) + nread, length - nread); if(nr > 0){ nread += static_cast<int>(nr); } else if(nr == 0){ break; } else if(errno != EINTR){ perror("read"); break; } } return nread;}int write_n(int sockfd, const void * buf, int length){ int nwrite = 0; while(nwrite < length){ ssize_t nw = write(sockfd, static_cast<const char *>(buf) + nwrite, length - nwrite); if(nw > 0){ nwrite += static_cast<int>(nw); } else if(nw == 0){ break; //EOF } else if(errno != EINTR){ perror("read"); break; } } return nwrite;}void transmit(const Options & opt){ //建立连接 struct sockaddr_in addr = resolveAddr(opt.host.c_str(), opt.port); printf("connecting to %s:%d\n", inet_ntoa(addr.sin_addr), opt.port); int sockfd = socket(AF_INET, SOCK_STREAM, 0); assert(sockfd > 0); int connfd = connect(sockfd, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr)); if(connfd == -1){ perror("connect"); printf("Unable to connect %s\n", opt.host.c_str()); close(sockfd); return ; } printf("connected\n"); // start timing muduo::Timestamp start(muduo::Timestamp::now()); // construct sessionMessage struct SessionMessage sessionMessage = {0, 0}; sessionMessage.number = ntohl(opt.number); sessionMessage.length = ntohl(opt.length); // send sessionMessage if(write_n(sockfd, &sessionMessage, sizeof(sessionMessage)) != sizeof(sessionMessage)){ perror("write SessionMessage"); exit(1); } // construct payload const int total_len = static_cast<int>(sizeof(int32_t) + opt.length); PayloadMessage * payload = static_cast<PayloadMessage*>(malloc(total_len)); assert(payload); payload->length = htonl(opt.length); for(int i = 0; i < opt.length; i++){ payload->data[i] = "0123456789ABCDEF"[i%16]; } double total_mb = 1.0 * opt.length * opt.number / 1024 / 1024; printf("%.3f MiB in total\n", total_mb); // send PayloadMessage for(int i = 0; i < opt.number; i++){ int nw = write_n(sockfd, payload, total_len); assert(nw == total_len); int ack = 0; //god job! the ack package is 4 byte, sizeof(int)!; int nr = read_n(sockfd, &ack, sizeof(ack)); assert(nr == sizeof(ack)); ack = ntohl(ack); assert(ack == opt.length); } //释放内存 free(payload); //关闭sock连接 close(sockfd); //计算总共所用时间和传输速率 double elapsed = timeDifference(muduo::Timestamp::now(), start); printf("%.3f seconds\n%.3f MiB/s\n",elapsed, total_mb / elapsed);}void receive(const Options &opt){ int sockfd = acceptCli(opt.port); struct SessionMessage sessionMessage = {0, 0}; if(read_n(sockfd, &sessionMessage, sizeof(sessionMessage)) != sizeof(sessionMessage)){ perror("read SessionMessage"); exit(1); } sessionMessage.number = ntohl(sessionMessage.number); sessionMessage.length = ntohl(sessionMessage.length); printf("receive number = %d\n receive length = %d\n", sessionMessage.number, sessionMessage.length); const int total_len = static_cast<int>(sizeof(int32_t) + sessionMessage.length); PayloadMessage * payload = static_cast<PayloadMessage*>(malloc(total_len)); assert(payload); //接收payload for(int i = 0; i < sessionMessage.number; i++){ payload->length = 0; if(read_n(sockfd, &payload->length, sizeof(payload->length)) != sizeof(payload->length)){ perror("read length"); exit(1); } payload->length = ntohl(payload->length); assert(payload->length == sessionMessage.length); if(read_n(sockfd, payload->data, payload->length) != payload->length){ perror("read payload data"); exit(1); } int32_t ack = htonl(payload->length); if(write_n(sockfd, &ack, sizeof(ack)) != sizeof(ack)){ perror("write ack"); exit(1); } } free(payload); close(sockfd);}
//protocol.h#pragma once#include <stdint.h>struct SessionMessage{ int32_t number; int32_t length;};struct PayloadMessage{ int32_t length; //usage: PayloadMessage * payload = static_cast<PayloadMessage *>(::malloc(total_len)); char data[0];};
//makefile 这个makefile的库我采用了相对路径,仅供参考。test:commandLineParser.o clientAndServer.o main.o g++ commandLineParser.o clientAndServer.o main.o -o test -L../../../build/release-install/lib -lmuduo_net -lmuduo_base -lboost_program_optionscommandLineParser.o:commandLineParser.h commandLineParser.cc g++ -c commandLineParser.cc -o commandLineParser.oclientAndServer.o:clientAndServer.cc clientAndServer.h g++ -c clientAndServer.cc -o clientAndServer.o -I../../../build/release-install/includemain.o: g++ -c main.cc -o main.o -I../../../build/release-install/includeclean: rm -rf *.o test
//用wc -l *.h *.cc 命令算出总共318行代码
//性能测试后续给出
未完待续…
3 0
- C++后台开发 网络编程实践一
- 网络编程最佳实践一
- [todo]后台开发面试 网络编程 数据库
- 网络编程实践陈硕笔记一
- C#.NET网络程序开发的基本类(一)(C#---网络编程)
- Java 开发实践 网络编程 详解
- Linux C语言 网络编程(一)
- 网络编程TCP总结及实践-C语言
- 网络编程UDP总结及实践-C语言
- ios开发 网络编程浅析(一)
- iOS开发之网络编程(一)
- Android开发之网络编程(一)
- Java开发实践 网络编程 学习、应用、总结
- J2ME网络编程实践
- 网络编程最佳实践
- Android 网络编程实践
- linux网络编程实践
- 网络编程的实践
- android app性能优化大汇总(UI渲染性能优化)
- 对于php、mysql优化、angularjs的一些小感悟
- leetcode-504-Diameter of Binary Tree
- poj 2142 数论 扩展欧几里得
- leetcode-504-Diameter of Binary Tree
- C++后台开发 网络编程实践一
- boost库入门
- Servlet分页技术
- 三种简单排序算法
- JavaScript-正则表达式
- C++STL库之algorithm库
- javaScript之String字符串
- java菜鸟回炉之旅之二----认识java
- shell基础-bash基本功能-别名与快捷键