頓悟,以前浪費了大把光陰。。痛惜!node
決定落戶到oschina了,支持開源。先貼上CSDN已發表過的。linux
測試目的:比較c,c++,node.js,erlang網絡TCP讀寫性能ios
測試環境:linuxc++
測試條件:Server爲簡單的TCP echo服務器,Server和Client運行在同一機器上,10000長鏈接,100活動鏈接服務器
測試結果:網絡
c++ boost::asio
connect=10000,active connect=100,req=148791,time=60,req/sec=2479.85,msec/req=40.343
erlang kernel-poll false
connect=10000,active connect=100,req=979803,time=60,req/sec=16330,msec/req=6.12356
node.js
connect=10000,active connect=100,req=1378370,time=60,req/sec=22972.8,msec/req=4.35543
c libevent
connect=10000,active connect=100,req=3719106,time=60,req/sec=61985.1,msec/req=1.61258
erlang kernel-poll true
connect=10000,active connect=100,req=6377574,time=60,req/sec=106293,msec/req=0.939882session
源代碼見下:socket
asio_echo_server.cppasync
#include <cstdlib> #include <iostream> #include <boost/bind.hpp> #include <boost/asio.hpp> #include <boost/thread/thread.hpp> using boost::asio::ip::tcp; int total_conn = 0; class session { public: session(boost::asio::io_service& io_service) : socket_(io_service) { } tcp::socket& socket() { return socket_; } void start() { socket_.async_read_some(boost::asio::buffer(data_, max_length), boost::bind(&session::handle_read, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); } private: void handle_read(const boost::system::error_code& error, size_t bytes_transferred) { if (!error) { boost::asio::async_write(socket_, boost::asio::buffer(data_, bytes_transferred), boost::bind(&session::handle_write, this, boost::asio::placeholders::error)); } else { delete this; } } void handle_write(const boost::system::error_code& error) { if (!error) { socket_.async_read_some(boost::asio::buffer(data_, max_length), boost::bind(&session::handle_read, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); } else { delete this; } } tcp::socket socket_; enum { max_length = 1024 }; char data_[max_length]; }; class server { public: server(boost::asio::io_service& io_service, short port) : io_service_(io_service), acceptor_(io_service, tcp::endpoint(tcp::v4(), port)) { start_accept(); } private: void start_accept() { session* new_session = new session(io_service_); acceptor_.async_accept(new_session->socket(), boost::bind(&server::handle_accept, this, new_session, boost::asio::placeholders::error)); } void handle_accept(session* new_session, const boost::system::error_code& error) { start_accept(); if (!error) { std::cout << "total connect =" << ++total_conn <<std::endl; new_session->start(); } else { delete new_session; } } boost::asio::io_service& io_service_; tcp::acceptor acceptor_; }; int main(int argc, char* argv[]) { try { if (argc < 2) { std::cerr << "Usage: async_tcp_echo_server <port>\n"; return 1; } boost::asio::io_service io_service; using namespace std; // For atoi. server s(io_service, atoi(argv[1])); int thread_num = 6; if (argc > 2) thread_num = atoi(argv[2]); boost::thread_group th_group; for (int i=0; i<thread_num; ++i) { th_group.add_thread(new boost::thread(boost::bind(&boost::asio::io_service::run, &io_service))); } th_group.join_all(); } catch (std::exception& e) { std::cerr << "Exception: " << e.what() << "\n"; } return 0; }
libevent-echo-server.ctcp
#include <stdlib.h> #include <unistd.h> #include <netinet/in.h> #include <sys/socket.h> #include <sys/types.h> #include <sys/socket.h> #include <event.h> #include <stdio.h> #include <time.h> #include <string.h> #include <fcntl.h> int buf_len = 8192; int msg_len = 4096; int total = 0; int setnonblock(int fd) { int flags; flags = fcntl(fd, F_GETFL); if (flags < 0) return flags; flags |= O_NONBLOCK; if (fcntl(fd, F_SETFL, flags) < 0) return -1; return 0; } void connection_echo(int fd, short event, void *arg) { struct event *ev = (struct event *)arg; event_add(ev, NULL); char buf[buf_len]; int read_len = read(fd, buf, msg_len); write(fd, buf, read_len); } void connection_accept(int fd, short event, void *arg) { /* for debugging */ fprintf(stderr, "%s(): fd = %d, event = %d, total = %d.\n", __func__, fd, event, ++total); /* Accept a new connection. */ struct sockaddr_in s_in; socklen_t len = sizeof(s_in); int ns = accept(fd, (struct sockaddr *) &s_in, &len); if (ns < 0) { perror("accept"); return; } setnonblock(ns); /* Install echo server. */ struct event *ev = (struct event *)malloc(sizeof(struct event)); event_set(ev, ns, EV_READ, connection_echo, ev); event_add(ev, NULL); } int main(void) { /* Request socket. */ int s = socket(PF_INET, SOCK_STREAM, 0); if (s < 0) { perror("socket"); exit(1); } /* bind() */ struct sockaddr_in s_in; memset(&s_in, 0, sizeof(s_in)); s_in.sin_family = AF_INET; s_in.sin_port = htons(9000); s_in.sin_addr.s_addr = INADDR_ANY; if (bind(s, (struct sockaddr *) &s_in, sizeof(s_in)) < 0) { perror("bind"); exit(1); } /* listen() */ if (listen(s, 1000) < 0) { perror("listen"); exit(1); } /* Initial libevent. */ event_init(); /* Create event. */ struct event ev; event_set(&ev, s, EV_READ | EV_PERSIST, connection_accept, &ev); /* Add event. */ event_add(&ev, NULL); event_dispatch(); return 0; }
erlang-echo-server.erl
-module(echo_server). -export([start/0]). start() -> {ok, Listen} = gen_tcp:listen(9000, [binary, %{packet, 4}, {reuseaddr, true}, {backlog, 2000}, {active, true}]), spawn(fun() -> par_connect(Listen, 0) end). par_connect(Listen, Count) -> {ok, Socket} = gen_tcp:accept(Listen), New = Count + 1, io:format("Accept succ ~p~n", [New]), spawn(fun() -> par_connect(Listen, New) end), loop(Socket). loop(Socket) -> receive {tcp, Socket, Bin} -> gen_tcp:send(Socket, Bin), loop(Socket); {tcp_closed, Socket} -> io:format("Server socket closed~n") end.
node-echo-server.js
var net = require('net'); var cnt = 0; var server = net.createServer(function (socket) { socket.pipe(socket); }); server.listen(9000, "127.0.0.1"); console.log('Server running at 127.0.0.1:9000');