TCP send频繁调用有多耗?测试过每次花费0.1毫秒?那些号称每秒几十万次的靠谱吗?

testtcpsend 发布于 2016/08/29 18:10
阅读 1K+
收藏 0
TCP send频繁调用有多耗?测试过每次花费0.1毫秒?那些号称每秒几十万次的靠谱吗?
加载中
0
乌龟壳
乌龟壳
懒得看代码了,试一下TCP_NO_DELAY
t
testtcpsend
回复 @乌龟壳 : 这么说就释然了, 十分感谢!
乌龟壳
乌龟壳
回复 @testtcpsend : 原来你纠结在这里,人家可能是几台机器一起send,还有一个比较好的服务器都几十个CPU加万兆的局域网
t
testtcpsend
@乌龟壳 嗯, 之前就怀疑是cpu流水线cache之类的问题,虽然不占CPU,但是别人都号称能够每秒几万次send,那依这个数据来看,因为业务必须要执行其他代码不能一直send,那等业务执行完毕再send就是这么慢,那是怎么做到的?还是他们的结果是建立在连续send上的?
乌龟壳
乌龟壳
回复 @testtcpsend : 如果对延迟有极高的要求,建议去研究实时系统那方面。
乌龟壳
乌龟壳
回复 @testtcpsend : 如果那段for换成sleep,就只有第一个会慢,如果用for就两个都慢,基本可以认为是CPU流水线的问题了。但是差距只在十分之一毫秒之内。
下一页
1
iBoxDB
iBoxDB

有探索精神,别人测试的可不是普通服务器而是超级计算机。

http://my.oschina.net/iboxdb/blog/404957

t
testtcpsend
谢谢,我了解一下
1
ked
ked
几十万次可不是一台机器啊,是集群。
t
testtcpsend
补充一下,单台硬件并且单线程的能达到几万次吗?
t
testtcpsend
单台几万次呢?
0
t
testtcpsend

2w次就差不多要花费2秒了, 每秒几万上十万次怎么做到的?

i7, 16G,ubuntu测试

0
g
gzgz8080
把小包合成打包,减少调用
t
testtcpsend
假设每次已经合并了呢?我只是怀疑那些每秒发送上万次的程序, 如果他们可以做到就是我做错了,因此我需要证明的是每秒几万次cpu还不高是可行的?
0
t
testtcpsend
高手何在?
0
老汉-憨憨
老汉-憨憨

send 并不是立马把数据发送出去给对方,而是放入内核对应的缓存区。

SO_SNDBUF

SO_RCVBUF

setsockopt

getsockopt

t
testtcpsend
这个我知道, 看别人测试libevent说每秒能echo回显8万次, 我测试单次send的消耗是0.1毫秒左右, 8万次是8秒才能做到,我就糊涂了, 是我哪里做错了?
0
songtzu
songtzu
明确告诉你,靠谱。大多数企业能做到1w+的tps(含业务的请求),撇开业务,无复杂业务的IO,10w+很轻松的。
songtzu
songtzu
回复 @testtcpsend : 测评都是指单服,集群测试比较复杂。单核单线程,只适用无业务的请求,也就是俗话说的玩具。
t
testtcpsend
补充一下,单台硬件并且单线程的能达到几万次吗??
0
0x0001
0x0001
刚测试, java8, i5-4570 8G内存, 本地测试, 30W每秒发送
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Created by 0x0001 on 2016/8/30.
 */
public class NioTest {
	private static void server() {
		ServerSocketChannel serverSocketChannel;
		Selector selector;

		try {
			selector = Selector.open();

			serverSocketChannel = ServerSocketChannel.open();
			serverSocketChannel.configureBlocking(false);
			serverSocketChannel.bind(new InetSocketAddress("127.0.0.1", 8888), 1024);

			serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

		} catch (IOException e) {
			throw new RuntimeException(e);
		}

		ByteBuffer buffer = ByteBuffer.allocate(8192);

		while(true) {
			try {
				selector.select();
			} catch (IOException e) {
				throw new RuntimeException(e);
			}

			for (Iterator<SelectionKey> iter = selector.selectedKeys().iterator(); iter.hasNext(); iter.remove()) {
				SelectionKey key = iter.next();
				if (key.isAcceptable()) {
					try {
						SocketChannel client = serverSocketChannel.accept();
						if (client.finishConnect()) {
							client.configureBlocking(false);
							client.register(selector, SelectionKey.OP_READ);
						}
					} catch (IOException e) {
						e.printStackTrace();
					}
					continue;
				}

				if (key.isReadable()) {
					SocketChannel client = (SocketChannel) key.channel();
					try {
						int read = client.read(buffer);
						if (read == -1) {
							key.cancel();
						}
					} catch (IOException e) {
						e.printStackTrace();
						key.cancel();
					}
					buffer.clear();
				}
			}
		}
	}

	private static void client() {
		Selector selector;
		try {
			selector = Selector.open();

			for (int i = 0; i < 10; i++) {
				SocketChannel client = SocketChannel.open();
				client.configureBlocking(false);
				client.connect(new InetSocketAddress("127.0.0.1", 8888));

				client.register(selector, SelectionKey.OP_CONNECT);
			}
		} catch(IOException e) {
			throw new RuntimeException(e);
		}

		ByteBuffer buffer = ByteBuffer.wrap(new byte[512]);

		ByteBuffer read = ByteBuffer.allocate(512);

		AtomicInteger sendCount = new AtomicInteger();

		new Thread(()->{
			while(true) {
				try {
					TimeUnit.SECONDS.sleep(1);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println("sendCount = " + sendCount);
				sendCount.set(0);
			}
		}).start();

		while(true) {
			try {
				selector.select();
			} catch (IOException e) {
				throw new RuntimeException(e);
			}

			for (Iterator<SelectionKey> iter = selector.selectedKeys().iterator(); iter.hasNext(); iter.remove()) {
				SelectionKey key = iter.next();
				SocketChannel sc = (SocketChannel) key.channel();

				if (key.isConnectable()) {
					try {
						sc.finishConnect();
					} catch (IOException e) {
						e.printStackTrace();
						key.cancel();
					}
					key.interestOps(SelectionKey.OP_WRITE);
				} else if (key.isWritable()) {
					try {
						sc.write(buffer);
						sendCount.incrementAndGet();
					} catch (IOException e) {
						key.cancel();
						e.printStackTrace();
					}
					if(!buffer.hasRemaining()) {
						buffer.flip();
					}
				} else if (key.isReadable()) {
					try {
						if (-1 == sc.read(read)) {
							key.cancel();
						}
					} catch (IOException e) {
						e.printStackTrace();
						key.cancel();
					}
				}
			}

		}
	}

	public static void main(String[] args) throws Exception {

		Runnable server = NioTest::server;
		Runnable client = NioTest::client;

		ExecutorService executorService = Executors.newFixedThreadPool(2);
		executorService.execute(server);

		// wait server start up
		TimeUnit.SECONDS.sleep(2);

		executorService.execute(client);
	}
}



0x0001
0x0001
回复 @testtcpsend : 不懂c艹
t
testtcpsend
有c++的吗?
0
t
testtcpsend

附上我的测试代码和结果:

#include<sys/types.h>
 #include<sys/socket.h>
 #include<netinet/in.h>
 #include<arpa/inet.h>
 #include<unistd.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <strings.h>
 #include<sys/wait.h>
 #include <string.h>
#include <time.h> 
#include <unistd.h>
 #include <fcntl.h>
#include <sys/time.h>
#include <stdio.h>
#include  <netinet/in.h>
 #include <netinet/tcp.h> // for TCP_NODELAY
#include <sys/time.h>
#include <sys/epoll.h>
#include <time.h>

typedef unsigned int            uint32_t; 
	void xsleep(uint32_t ms)
	{ 
	  struct timeval tval;
	  tval.tv_sec	= ms / 1000;
	  tval.tv_usec	= ( ms * 1000) % 1000000;
	  select(0, NULL, NULL, NULL, &tval);
	}	


 int main(int argc, char ** argv) 
 { 
     int sockfd,new_fd;
     struct sockaddr_in my_addr;
     struct sockaddr_in their_addr;
     unsigned int sin_size, myport, lisnum; 
  
     if(argv[1])  myport = atoi(argv[1]); 
     else myport = 50000; 
  
     if(argv[2])  lisnum = atoi(argv[2]); 
     else lisnum = 2; 
  
     if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) { 
         perror("socket"); 
         exit(1); 
     } 
  printf("socket %d ok \n",myport);
//fcntl(sockfd, F_SETFL, O_NONBLOCK);
    my_addr.sin_family=PF_INET; 
     my_addr.sin_port=htons(myport); 
     my_addr.sin_addr.s_addr = INADDR_ANY; 
     bzero(&(my_addr.sin_zero), 0); 
     if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) { 
         perror("bind"); 
         exit(1); 
     } 
  printf("bind ok \n");
  
     if (listen(sockfd, lisnum) == -1) { 
         perror("listen"); 
         exit(1); 
     }
  printf("listen ok \n");
  


    sin_size = sizeof(struct sockaddr_in); 

xxx:
     if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) == -1) { 
         perror("accept"); 
   goto xxx;
     } 



     printf("server: got connection from %s\n",inet_ntoa(their_addr.sin_addr));
fcntl(new_fd, F_SETFL, O_NONBLOCK);
int arg = 1;
setsockopt(new_fd, IPPROTO_TCP, TCP_NODELAY, (char*)&arg, sizeof(int));
int nSendBuf=1024*1024*16;//¨¦??32K
setsockopt(new_fd,SOL_SOCKET,SO_SNDBUF,(const char*)&nSendBuf,sizeof(int)); 


int epfd;
struct epoll_event ev,events[20];
epfd=epoll_create(256);

ev.data.fd=sockfd;
ev.events=EPOLLIN|EPOLLOUT;
epoll_ctl(epfd,EPOLL_CTL_ADD,sockfd,&ev);

ev.data.fd=new_fd;
ev.events=EPOLLIN|EPOLLOUT;
epoll_ctl(epfd,EPOLL_CTL_ADD,new_fd,&ev);



 int   step = 0;
   char  szSnd[1024] = {0};
   memset(szSnd,97,1024);
szSnd[100] = 0;

//time_t lasttime = time(NULL);
struct timeval lasttime;
gettimeofday(&lasttime,0);
double alltimeuse = 0.0;


int iii = 0;
while(iii++<100)
{
struct timeval lasttime;
gettimeofday(&lasttime,0);

 if (send(new_fd, szSnd, strlen(szSnd), 0) == -1) {
     perror("send");
 }


struct timeval now_time;
gettimeofday(&now_time,0);
double timeuse = 1000000.0*(now_time.tv_sec - lasttime.tv_sec) + now_time.tv_usec - lasttime.tv_usec;
timeuse /=1000.0;
 printf("xxsend msg: %f\n",(timeuse));



{
struct timeval lasttime;
gettimeofday(&lasttime,0);

 if (send(new_fd, szSnd, strlen(szSnd), 0) == -1) {
     perror("send");
 }


struct timeval now_time;
gettimeofday(&now_time,0);
double timeuse = 1000000.0*(now_time.tv_sec - lasttime.tv_sec) + now_time.tv_usec - lasttime.tv_usec;
timeuse /=1000.0;
 printf("xxsend1 msg: %f\n",(timeuse));
}

for(int ccc=0; ccc<1000000; ccc++)
   {
char aaax[10240];
memset(aaax,0,10240);
}
//xsleep(100);
//usleep(1000);
};

 exit(0); 
 }


测试结果:可见第一次send很慢, 第二次send1很快, 如果while循环一直连续send就超快, 几十万次的确小意思, 但是一旦期间有其他代码执行下一次send就超慢, 在现实业务中肯定send完之后要做其他事情, 为何会这样?

socket 50000 ok
bind ok
listen ok
server: got connection from 192.168.125.69
xxsend msg: 0.327000
xxsend1 msg: 0.126000
xxsend msg: 0.058000
xxsend1 msg: 0.041000
xxsend msg: 0.028000
xxsend1 msg: 0.002000
xxsend msg: 0.929000
xxsend1 msg: 0.002000
xxsend msg: 0.045000
xxsend1 msg: 0.002000
xxsend msg: 0.068000
xxsend1 msg: 0.045000
xxsend msg: 0.054000
xxsend1 msg: 0.001000
xxsend msg: 0.044000
xxsend1 msg: 0.040000
xxsend msg: 0.029000
xxsend1 msg: 0.023000
xxsend msg: 3.455000
xxsend1 msg: 0.002000
xxsend msg: 0.050000
xxsend1 msg: 0.028000
xxsend msg: 0.061000
xxsend1 msg: 0.002000
xxsend msg: 0.049000
xxsend1 msg: 0.036000
xxsend msg: 0.179000
xxsend1 msg: 0.035000
xxsend msg: 0.048000
xxsend1 msg: 0.001000
xxsend msg: 0.058000
xxsend1 msg: 0.012000
xxsend msg: 0.053000
xxsend1 msg: 0.001000
xxsend msg: 0.065000
xxsend1 msg: 0.001000
xxsend msg: 0.030000
xxsend1 msg: 0.011000
xxsend msg: 0.151000
xxsend1 msg: 0.002000
xxsend msg: 0.059000
xxsend1 msg: 0.003000
xxsend msg: 0.054000
xxsend1 msg: 0.001000
xxsend msg: 0.053000
xxsend1 msg: 0.002000
xxsend msg: 0.047000
xxsend1 msg: 0.002000
xxsend msg: 0.045000
xxsend1 msg: 0.002000
xxsend msg: 0.118000
xxsend1 msg: 0.002000
xxsend msg: 0.143000
xxsend1 msg: 0.002000


返回顶部
顶部