socket效率到底如何
来源:互联网 发布:linux下codeblocks 编辑:程序博客网 时间:2024/05/22 07:42
两台服务器用千兆交换机连接,带宽为1000Mbps,socket的效率到底如何?若server尽量快向client写数据,client收到数据后就丢弃,是否能占满千兆带宽?
测试发现和每次发送的包大小有关系,TCP包为1000bits(125字节)以上就能占满带宽:
因此,若client足够多而且都在请求数据,但是带宽上不去,就是服务器程序的问题了。
协议本身会降低带宽,使用rtmp协议的server一个进程带宽上限估计在260Mbps(若使用阻塞模式只能到150Mbps左右),能服务570个客户端(码流为500kbps),或者能服务870个客户端(300kbps),再有新的client过来会有延时就不行了。不过使用多进程,这台server还可以多启动进程,这样就可以将带宽占满,或者和FMS一样服务其他的vhost。
rtmp默认的chunk size为128,若使用这个尺寸发包,server只能到260Mbps(见上)。但将ChunkSize设为1100以上(和表中一样),带宽就能到945Mbps,能占满千兆网所有带宽。(rtmp server对rtmp client或tcp client都能占满带宽)
估计rtmp协议的效率如下,假设客户端的缓冲区设为10秒:
1. 选择视频为11Mbps时,只需要100个client即可跑满1000Mbps带宽,实际430Mbps(估计Server效率不行)。CPU很低只有14%。vmstat显示cs在12459,in为14439,比较高。内存使用1.8G。首次加载时间稍稍变慢需要2秒左右,seek后加载速度明显变慢需要10秒。预计CPU在18%左右。
2. 选择视频为900Kbps时,需要1000个客户端跑满1000Mbps带宽。实际上只能跑到300Mbps。CPU很低只有4%。vmstat显示cs在11360,in为1943,比较高。内存使用165M。首次加载时间和seek时间不变。预计CPU在72%左右。
3. 实际上单个进程不可能跑满945Mbps带宽,那个时候client的延迟已经很大了。2000个300Kbps的客户端,跑到500Mbps左右,单个进程,保持每个client都不延迟,已经是很好的设计了。支持高并发,必须要单线程和异步,使用多线程会显著增加开销(非线性)。
4. printf打日志对系统负载有影响,若打出的日志很多,会有影响。程序保持高性能,就是不block同时尽量不做和效率无关的事情。
测试程序如下:
// simple-server: send data as fast as possible.#include <stdio.h>#include <stdlib.h>#include <assert.h>#include <iostream>using namespace std;#include <unistd.h>#include <signal.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <sys/wait.h>#include <sys/epoll.h>#include <string.h>#include <errno.h>#define err_exit(msg) cout << "[error] " << msg << endl; exit(1)struct UserOptions{ int port; int packet_size;};void discovery_user_options(int argc, char** argv, UserOptions& options){ if(argc <= 2){ cout << "Usage: " << argv[0] << " <port> <packet_size>" << endl << "port: the port to listen" << endl << "packet_size: the packet size in b. must >= 8" << endl << "For example: " << argv[0] << " 1990 1000" << endl; exit(1); } options.port = atoi(argv[1]); options.packet_size = atoi(argv[2]); assert(options.port > 0); assert(options.packet_size >= 8);}int listen_server_socket(UserOptions& options){ int serverfd = socket(AF_INET, SOCK_STREAM, 0); if(serverfd == -1){ err_exit("init socket error!"); } cout << "init socket success! #" << serverfd << endl; int reuse_socket = 1; if(setsockopt(serverfd, SOL_SOCKET, SO_REUSEADDR, &reuse_socket, sizeof(int)) == -1){ err_exit("setsockopt reuse-addr error!"); } cout << "setsockopt reuse-addr success!" << endl; sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(options.port); addr.sin_addr.s_addr = INADDR_ANY; if(bind(serverfd, (const sockaddr*)&addr, sizeof(sockaddr_in)) == -1){ err_exit("bind socket error!"); } cout << "bind socket success!" << endl; if(listen(serverfd, 10) == -1){ err_exit("listen socket error!"); } cout << "listen socket success! " << options.port << endl; return serverfd;}int main(int argc, char** argv){ UserOptions options; discovery_user_options(argc, argv, options); int serverfd = listen_server_socket(options); while(true){ int client = accept(serverfd, NULL, 0); alarm(60); cout << "get a client #" << client << ", packet size=" << options.packet_size << "b" << endl; if(client == -1){ err_exit("accept client socket error!"); } int size = options.packet_size / 8; char* data = new char[size]; while(true){ if(send(client, data, size, 0) == -1){ close(client); cout << "send client error!" << endl; break; } } } return -1;}
// simple-client recv data and delete it.#include <stdio.h>#include <stdlib.h>#include <iostream>#include <assert.h>using namespace std;#include <unistd.h>#include <signal.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <string.h>#define err_exit(msg) cout << "[error] " << msg << endl; exit(1)struct UserOptions{ char* server_ip; int port;};void discovery_user_options(int argc, char** argv, UserOptions& options){ if(argc <= 2){ cout << "Usage: " << argv[0] << " <server_ip> <port>" << endl << "server_ip: the ip address of server" << endl << "port: the port to connect at" << endl << "For example: " << argv[0] << " 192.168.100.145 1990" << endl; exit(1); } options.server_ip = argv[1]; options.port = atoi(argv[2]); assert(options.port > 0);}int connect_server_socket(UserOptions& options){ int clientfd = socket(AF_INET, SOCK_STREAM, 0); if(clientfd == -1){ err_exit("init socket error!"); } cout << "init socket success!" << endl; sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(options.port); addr.sin_addr.s_addr = inet_addr(options.server_ip); if(connect(clientfd, (const sockaddr*)&addr, sizeof(sockaddr_in)) == -1){ err_exit("connect socket error!"); } cout << "connect socket success!" << endl; return clientfd;}int main(int argc, char** argv){ UserOptions options; discovery_user_options(argc, argv, options); int client = connect_server_socket(options); int size = 100 /*kbps*/ * 1000 / 8; char* buf = new char[size]; while(true){ if(recv(client, buf, size, 0) <= 0){ close(client); err_exit("client recv error!"); } } return 0;}
- socket效率到底如何
- Qt图形视图框架到底效率如何?
- 到底如何
- socket编程到底是什么
- Socket到底是什么?
- 到底该如何理解socket的阻塞/非阻塞/同步/异步
- 到底如何学习java
- 到底如何学习数据结构?
- 到底如何理解递归?
- 如何提高阅读效率
- 如何提高编码效率
- 如何提高阅读效率
- 如何提高阅读效率
- 如何提高查询效率
- 如何提高测试效率
- 如何提高开发效率
- 如何提高头脑效率?
- 如何提高C++效率
- 关于第一次搜索的速度问题--HubbleDotNet----Hubble.net
- 如何编译openssl
- 二维数组排序
- 使用ControllerActionInvoker简化MVC单Form多按钮的提交
- Qt的QGraphicsView框架
- socket效率到底如何
- 变长数组
- 枚举 子集生成
- VMware 8虚拟机下,ubuntu系统如何安装 vmware tools
- HTML小知识一
- 程序员技术练级攻略
- Android基础教程(二)之五大布局对象---FrameLayout,LinearLayout ,AbsoluteLayout,RelativeLayout,TableLayout.
- 写一个完美数程序
- 让控制台程序也能拥有进度条