UDP接收速度100Mbps,CPU占用14%,为何效率如此之低?

hugeice 2012-12-01 05:04:12
我写了一个使用UDP协议通讯的客户端程序,功能是接收远程数据采集卡发送过来的数据。数据采集卡发送数据的速度大约为80Mbps (实际有效数据速率9.6MBytes/s),在一台4核心AMD处理器PC上接收数据正确,但是CPU占用高达14%。用VTune性能分析发现除了数据处理(可靠UDP传输)消耗了一定的时间外,select和recvfrom函数也消耗了大量的时间。
于是我自己写代码统计了下时间,接收60M数据总共花费6s左右,40k个包,花在recvfrom上的时间为350ms,每次调用花费8.75us!这个效率是不是太低了点!recvfrom应该是从协议栈的socket的接收缓冲copy数据到用户缓冲区呀,要知道现在内存速度都十几G字节每秒了。

主要是我们客户的电脑比较破,单核的老奔四,我的程序会占用超过90%的CPU,导致无法及时接收数据,数据传输率达不到预期目标,因此现在要想办法把这个CPU占用率降下来,请问各位有没有什么办法?


附:网上搜到“刘志胜”的博客有关于recvfrom的效率的说明:“http://blog.csdn.net/l_z_s_001/article/details/4699601”;
按照其文章中所说,UDP协议用1472字节的数据包发包,最多只能达到200Mbps;如果用20K字节数据包发包,经过协议栈进行IP分片,发送速度能到1Gbps! 但是我的应用IP包不能分片!(对端数据采集设备不支持!),还有没有别的方法呢?
...全文
4017 59 打赏 收藏 转发到动态 举报
写回复
用AI写文章
59 条回复
切换为时间正序
请发表友善的回复…
发表回复
yuhaoloen 2013-10-03
  • 打赏
  • 举报
回复
话说千兆网卡有个 设置是设置巨型帧 在intel的千兆网卡中可以设置巨型帧 没帧 9000多字节 这个设置是用来减少网络传输过程中导致cpu使用率过高的一个 解决方案 不知道楼主现在这个问题解决了么
hugeice 2013-03-21
  • 打赏
  • 举报
回复
不好意思这么久才来结贴,多谢Squall_zy发送演示代码,感谢参与讨论的网友。 最终解决办法:在发送端实现了IP分片,采用大IP包的方式发送,一个IP包分成16片。此时PC端接收速度仍为10MB/s,但是CPU占用率下降到原来不采用IP分片时的30%左右,已经能够接受了。 另外,我测试了采用重叠IO方式,CPU占用率与采用select模型基本看不出区别(CPU占用率一直在小幅波动,肉眼看不出两种方式的区别),为了保证可移植性,最后还是采用select模型。
hugeice 2012-12-23
  • 打赏
  • 举报
回复
引用 49 楼 Squall_zy 的回复:
你给的邮箱好像有问题,不能送达。你换个邮箱吧。 Undelivered Mail Returned to Sender <hugeice@gmail.com>: host gmail-smtp-in.l.google.com[173.194.79.27] said: 552-5.7.0 Our system detected an illegal atta……
多谢Squall_zy网友的程序,经过测试,在P4 2.8G 超线程(1G内存)老机器上接受11.7MB/s数据量的1024字节UDP包: 1、不开任何程序,CPU占用14%,任务管理器打开“查看内核占用”选项,显示大约13%左右为内核占用 2、打开网友Squall_zy的接收程序,CPU占用17%,大约15%左右为内核占用 3、打开上面我发的那个程序,CPU占用45%,大约20%左右为内核占用 仔细对比了我的代码和网友Squall_zy的代码,发现我的程序中大部分多出来的CPU时间是这个函数占用的“int _kbhit(void)”,去掉之后我的程序启动后CPU占用与Squall_zy的程序差不多。 另外,我对比了用重叠IO和直接用recvfrom接收,CPU占用上看不出差别! 小结一下: 10MB/s的UDP包接收,应用层应该只消耗极少的CPU时间,但内核可能会占用CPU高达10%以上!
qazjiguangmin521 2012-12-21
  • 打赏
  • 举报
回复
新手看看来了
UDX协议 2012-12-21
  • 打赏
  • 举报
回复
我做过这样的测试,确实没有超过250MB的,如果你的超过了300MB,另外,你是以小包,1K为单位发送的,请告之在下。我的CPU比你的I5应该是强悍的,不知道你为何能跑300MB。 如果超过1K(1024字节)的包发送就完全无意义了。
UDX协议 2012-12-21
  • 打赏
  • 举报
回复
引用 53 楼 Squall_zy 的回复:
没和谁去比,都是技术上的讨论。 仅对你提出的“我认为,现在主流的系统,目前UDP不会超过250MB/S”的观点做一个反驳。 我也是在你的提醒下,做了一个这样的实验。
我的意思是,也是接前面sendto,和select recvfrom,来 说的,这种方式。 如果利用其他IO方式,当然是可以提高。 谈论前提不同,而且别人都有这样的测试。 另外,360测速超级不准,你最好在你的应用层界面上显示收发包的速度。
Squall_zy 2012-12-21
  • 打赏
  • 举报
回复
没和谁去比,都是技术上的讨论。 仅对你提出的“我认为,现在主流的系统,目前UDP不会超过250MB/S”的观点做一个反驳。 我也是在你的提醒下,做了一个这样的实验。
UDX协议 2012-12-21
  • 打赏
  • 举报
回复
引用 50 楼 Squall_zy 的回复:
引用 19 楼 wwwllg 的回复:目前来说,不管是IOCP,还是SENDTO,我还没有见过200M/S的,单个可靠连接,注意这个前提。 在我的I7 CPU, 3.5GHZ的环境下,已经相当牛B了吧。 VTCP可以传到180MB/S,UDX可以传到156MB/秒,VTCP是使用的IOCP,UDX使用的是一般的Sendto.单条连接。 所以,我认为,现在主流的系统,……
发送的包,1K为单位,你要是跑上300MB,算你牛B,另外,我们是可靠协议,代码要跑几百上千行才算跑了一圈,和你这个没一个比头。 笑,我很无耐,也无语。
xjb2001 2012-12-20
  • 打赏
  • 举报
回复
你收发包都没有 sleep ,CPU 不啃光才怪了
Squall_zy 2012-12-19
  • 打赏
  • 举报
回复
你给的邮箱好像有问题,不能送达。你换个邮箱吧。 Undelivered Mail Returned to Sender <hugeice@gmail.com>: host gmail-smtp-in.l.google.com[173.194.79.27] said: 552-5.7.0 Our system detected an illegal attachment on your message. Please 552-5.7.0 visit http://support.google.com/mail/bin/answer.py?answer=6590 to 552 5.7.0 review our attachment guidelines. qc4si3674179pbb.56 (in reply to end of DATA command)
Squall_zy 2012-12-19
  • 打赏
  • 举报
回复
引用 19 楼 wwwllg 的回复:
目前来说,不管是IOCP,还是SENDTO,我还没有见过200M/S的,单个可靠连接,注意这个前提。
在我的I7 CPU, 3.5GHZ的环境下,已经相当牛B了吧。
VTCP可以传到180MB/S,UDX可以传到156MB/秒,VTCP是使用的IOCP,UDX使用的是一般的Sendto.单条连接。
所以,我认为,现在主流的系统,目前UDP不会超过250MB/S




本机运行,数据只走协议栈,不通过网卡,可以上300MB/s。
实验数据,非IOCP,应用层无任何附加工作。
i5cpu、4G内存。
hugeice 2012-12-18
  • 打赏
  • 举报
回复
引用 43 楼 danscort2000 的回复:
你这个while代码太明显存在性能bug了 等于每个循环都需要计算统计时间 测试是否可继续写 初始化tv等等 你应该用2个循环 使用一个全局数字统计发送流量 while(!_kbhit( )) { while(!_kbhit( )) { ...... err = sendto(s, (char*……
去掉代码开头的#define USE_SELECT就没有select了,相当于不停调用sendto,测试性能没有任何变化!
hugeice 2012-12-18
  • 打赏
  • 举报
回复
引用 45 楼 Squall_zy 的回复:
建议: 1、你的接收缓冲区应该开大些(例如:512KB),否则会出现丢包。 2、接收部分应简洁。计时的函数可以去掉;select、FD_ISSET等全去掉,又不是多个套接字,要这玩意干嘛;对于阻塞方式的socket,定好超时,循环内一个recvfrom就好。 3、我的程序因为只测接收效率,并不做任何工作,所以cpu会低些。(我使用EventSelect方式) ……
去掉代码开头的#define USE_SELECT就没有select了,测试性能没有任何变化! 我的邮箱 hugeice@gmail.com ,能把你的程序发给我测试一下吗,先发二级制执行文件即可,谢谢!
Squall_zy 2012-12-17
  • 打赏
  • 举报
回复
建议: 1、你的接收缓冲区应该开大些(例如:512KB),否则会出现丢包。 2、接收部分应简洁。计时的函数可以去掉;select、FD_ISSET等全去掉,又不是多个套接字,要这玩意干嘛;对于阻塞方式的socket,定好超时,循环内一个recvfrom就好。 3、我的程序因为只测接收效率,并不做任何工作,所以cpu会低些。(我使用EventSelect方式)
Squall_zy 2012-12-17
  • 打赏
  • 举报
回复
不行你给我个邮箱,我发给你。 代码是个类,贴不下。程序也给你,自己测吧。vc2008平台。
danscort2000 2012-12-16
  • 打赏
  • 举报
回复
你这个while代码太明显存在性能bug了 等于每个循环都需要计算统计时间 测试是否可继续写 初始化tv等等 你应该用2个循环 使用一个全局数字统计发送流量 while(!_kbhit( )) { while(!_kbhit( )) { ...... err = sendto(s, (char*)buf, buf_size, 0, (struct sockaddr*)&sa, sizeof(sa)); if(err!=bufsize) break; else { itotal++;//发送包数量累加 } } Sleep(0); select 50ms 直到socket 可写 } //最后才输出统计结果
hugeice123 2012-12-15
  • 打赏
  • 举报
回复


////////////////////////////////////////////////////////////////
// app entry
////////////////////////////////////////////////////////////////

int main(int argc, char* argv[])
{
	WORD wVersionRequested = MAKEWORD( 2, 2 );
	WSADATA wsaData;
	int err = WSAStartup( wVersionRequested, &wsaData );
	if ( err != 0 ) {
		fprintf(stderr, "Initialize WinSock failed! error %d\n", err);
		return 0;
	}
 
	++argv;
	--argc;
	if ( argc > 0 ) {
		if ( stricmp(argv[0], "--help") == 0 || stricmp(argv[0], "-h") == 0 ) {
		} else if ( stricmp(argv[0], "tcp") == 0 ) {
			return tcp(argc, argv);
		} else if ( stricmp(argv[0], "udp") == 0 ) {
			return udp(argc, argv);
		} else {
			fprintf(stderr, "invalid parameter \"%s\"!\n", argv[0]);
		}
	}
	fprintf(stderr, "testnet\nusage: testnet tcp|udp [options]\n");
	return 0;
}

接收端如下调用: testnet udp recv 1234 131072绑定到1234端口接收,接收buffer大小为128KB 发送端如下调用: testnet udp send 192.168.1.66 1234 1024 发送到192.168.1.66的1234端口,发送包大小为1024字节,请将IP地址改为你的接收机的IP地址
hugeice123 2012-12-15
  • 打赏
  • 举报
回复
字数限制,回复限制,各种限制……
////////////////////////////////////////////////////////////////
// UDP
////////////////////////////////////////////////////////////////

// testnet udp recv [<bind port> [<buffer size>]]\n
int udp_recv(int argc, char* argv[])
{
	printf("udp_recv(server):\n");
	int port = 3000;
	if ( argc > 1 ) {
		if ( sscanf(argv[1], "%d", &port) != 1 ) {
			fprintf(stderr, "invalid udp port \"%s\"\n", argv[1]);
			return -1;
		}
	}
	int buf_size = 1024 * 1;
	if ( argc > 2 ) {
		if ( sscanf(argv[2], "%d", &buf_size) != 1 ) {
			fprintf(stderr, "invalid buffer size \"%s\"\n", argv[2]);
			return -2;
		}
	}
	LPBYTE buf = new BYTE[buf_size];
	if ( NULL == buf ) {
		perror("allocate buffer");
		return -3;
	}
	printf("buffer size %d\n", buf_size);
	SOCKET s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
	if ( INVALID_SOCKET == s ) {
		perror("creat UDP socket");
		return -4;
	}
	int recv_buf_size = buf_size * 2 + 1024 * 32;
	int err = setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char*)&recv_buf_size, sizeof(recv_buf_size));
	if ( err < 0 ) {
		perror("set socket recv buffer size");
		return -6;
	}
	struct sockaddr_in sa;
	memset(&sa, 0, sizeof(sa));
	sa.sin_family = AF_INET;
	sa.sin_addr.S_un.S_addr = INADDR_ANY;
	sa.sin_port = htons(port);
	err = bind(s, (struct sockaddr*)&sa, sizeof(sa));
	if ( err < 0 ) {
		perror("bind");
		return -5;
	}
	printf("bind to port %d\n", port);
	// recv loop
	int stat_bytes = 0;
	DWORD stat_last_time = timeGetTime();
	while ( !_kbhit() ) {
#ifdef USE_SELECT
		FD_SET fdr;
		FD_ZERO(&fdr);
		FD_SET(s, &fdr);
		struct timeval tv = {0, 50000};	// 50ms
		err = select(0, &fdr, NULL, NULL, &tv);
		if ( err < 0  )
			break;
		if ( err > 0 && FD_ISSET(s, &fdr) )
#endif/*USE_SELECT*/
		{
			int sa_len = sizeof(sa);
			err = recvfrom(s, (char*)buf, buf_size, 0, (struct sockaddr*)&sa, &sa_len);
			if ( err < 0 ) {
				perror("recv");
				return -7;
			}
			stat_bytes += err;
		}
		// Stat.
		DWORD time_now = timeGetTime();
		DWORD time_escape = time_now - stat_last_time;
		if ( time_escape >= 1000 ) {
			double speed_mb = (stat_bytes * 1000.0) / (time_escape * 1024.0 * 1024.0);
			printf("recv %.1fKB in %.1fs, speed is %.1fMB/s\n", stat_bytes / 1024.0, time_escape / 1000.0, speed_mb);
			stat_last_time = time_now;
			stat_bytes = 0;
		}
	}
	delete []buf;
	return 0;
}

// testnet udp send [<remote ip> <remote port> [<buffer size>]]
int udp_send(int argc, char* argv[])
{
	printf("udp_send(client):\n");
	unsigned long ip = inet_addr("127.0.0.1");
	if (argc > 1 ) { 
		ip = inet_addr(argv[1]);
		if ( 0 == ip ) {
			fprintf(stderr, "invalid IP address \"%s\"\n", argv[1]);
			return -1;
		}
	}
	int port = 3000;
	if ( argc > 2 ) {
		if ( sscanf(argv[2], "%d", &port) != 1 ) {
			fprintf(stderr, "invalid udp port \"%s\"\n", argv[2]);
			return -2;
		}
	}
	struct sockaddr_in sa;
	memset(&sa, 0, sizeof(sa));
	sa.sin_family = AF_INET;
	sa.sin_addr.S_un.S_addr = ip;
	sa.sin_port = htons(port);
	int buf_size = 1024 * 1;
	if ( argc > 3 ) {
		if ( sscanf(argv[3], "%d", &buf_size) != 1 ) {
			fprintf(stderr, "invalid buffer size \"%s\"\n", argv[3]);
			return -3;
		}
	}
	LPBYTE buf = new BYTE[buf_size];
	if ( NULL == buf ) {
		perror("allocate buffer");
		return -4;
	}
	for ( int i = 0; i < buf_size; i++ )
		buf[i] = (BYTE)i;
	printf("packet size %d\n", buf_size);
	SOCKET s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
	if ( INVALID_SOCKET == s ) {
		perror("creat UDP socket");
		return -5;
	}
	int send_buf_size = buf_size * 2 + 1024 * 32;
	int err = setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char*)&send_buf_size, sizeof(send_buf_size));
	if ( err < 0 ) {
		perror("set socket send buffer size");
		return -6;
	}
	// send loop
	int stat_bytes = 0;
	DWORD stat_last_time = timeGetTime();
	while ( !_kbhit() ) {
#ifdef USE_SELECT
		FD_SET fdw;
		FD_ZERO(&fdw);
		FD_SET(s, &fdw);
		struct timeval tv = {0, 50000};	// 50ms
		err = select(0, NULL, &fdw, NULL, &tv);
		if ( err < 0  )
			break;
		if ( err > 0 && FD_ISSET(s, &fdw) )
#endif/*USE_SELECT*/
		{
			err = sendto(s, (char*)buf, buf_size, 0, (struct sockaddr*)&sa, sizeof(sa));
			if ( err < 0 ) {
				perror("send");
				return -7;
			}
			stat_bytes += err;
		}
		// Stat.
		DWORD time_now = timeGetTime();
		DWORD time_escape = time_now - stat_last_time;
		if ( time_escape >= 1000 ) {
			double speed_mb = (stat_bytes * 1000.0) / (time_escape * 1024.0 * 1024.0);
			printf("send %.1fKB in %.1fs, speed is %.1fMB/s\n", stat_bytes / 1024.0, time_escape / 1000.0, speed_mb);
			stat_last_time = time_now;
			stat_bytes = 0;
		}
	}
	delete []buf;
	return 0;
}

int udp(int argc, char* argv[])
{
	printf("udp:\n");
	++argv;
	--argc;
	if ( argc > 0 ) {
		if ( stricmp(argv[0], "--help") == 0 || stricmp(argv[0], "-h") == 0 ) {
		} else if ( stricmp(argv[0], "recv") == 0 ) {
			return udp_recv(argc, argv);
		} else if ( stricmp(argv[0], "send") == 0 ) {
			return udp_send(argc, argv);
		} else {
			fprintf(stderr, "invalid parameter \"%s\"!\n", argv[0]);
		}
	}
	fprintf(stderr, "testnet udp recv [<bind port> [<buffer size>]]\n");
	fprintf(stderr, "testnet udp send [<remote ip> <remote port> [<buffer size>]]\n");
	return 0;
}
hugeice 2012-12-15
  • 打赏
  • 举报
回复
以下是我的完整测试程序,大家看看有什么问题,也可以用我的程序在你自己的机器上测试一下:
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <conio.h> // for _kbhit()
#include <Winsock2.h>
#pragma comment (lib, "Ws2_32.lib")
#include <Mmsystem.h> // for timeGetTime()
#pragma comment (lib, "Winmm.lib")

#define USE_SELECT

////////////////////////////////////////////////////////////////
// TCP
////////////////////////////////////////////////////////////////

// testnet tcp recv [<bind port> [<buffer size>]]\n
int tcp_recv(int argc, char* argv[])
{
	printf("tcp_recv(server):\n");
	int port = 3000;
	if ( argc > 1 ) {
		if ( sscanf(argv[1], "%d", &port) != 1 ) {
			fprintf(stderr, "invalid tcp port \"%s\"\n", argv[1]);
			return -1;
		}
	}
	int buf_size = 1024 * 32;
	if ( argc > 2 ) {
		if ( sscanf(argv[2], "%d", &buf_size) != 1 ) {
			fprintf(stderr, "invalid buffer size \"%s\"\n", argv[2]);
			return -2;
		}
	}
	LPBYTE buf = new BYTE[buf_size];
	if ( NULL == buf ) {
		perror("allocate buffer");
		return -3;
	}
	printf("buffer size %d\n", buf_size);
	SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if ( INVALID_SOCKET == s ) {
		perror("creat TCP socket");
		return -4;
	}
	int recv_buf_size = buf_size * 2 + 1024 * 32;
	int err = setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char*)&recv_buf_size, sizeof(recv_buf_size));
	if ( err < 0 ) {
		perror("set socket recv buffer size");
		return -6;
	}
	struct sockaddr_in sa;
	memset(&sa, 0, sizeof(sa));
	sa.sin_family = AF_INET;
	sa.sin_addr.S_un.S_addr = INADDR_ANY;
	sa.sin_port = htons(port);
	err = bind(s, (struct sockaddr*)&sa, sizeof(sa));
	if ( err < 0 ) {
		perror("bind");
		return -5;
	}
	printf("bind to port %d\n", port);
	err = listen(s, 1);
	if ( err < 0 ) {
		perror("listen");
		return -6;
	}
	// accept loop
	printf("wait for client connect ...\n");
	int sa_len = sizeof(sa);
	SOCKET sclient = INVALID_SOCKET;
	while ( !_kbhit() ) {
		FD_SET fdr;
		FD_ZERO(&fdr);
		FD_SET(s, &fdr);
		struct timeval tv = {0, 50000};	// 50ms
		err = select(0, &fdr, NULL, NULL, &tv);
		if ( err < 0  )
			break;
		if ( err > 0 && FD_ISSET(s, &fdr) ) {
			sclient = accept(s, (struct sockaddr*)&sa, &sa_len);
			break;
		}
	}
	if ( INVALID_SOCKET == sclient ) {
		printf("cancel\n");
		return 0;
	}
	printf("client %s:%d connected.\n", inet_ntoa(sa.sin_addr), ntohs(sa.sin_port));
	if ( _kbhit() ) _getch();	// clear key store
	// recv loop
	int stat_bytes = 0;
	DWORD stat_last_time = timeGetTime();
	while ( !_kbhit() ) {
#ifdef USE_SELECT
		FD_SET fdr;
		FD_ZERO(&fdr);
		FD_SET(sclient, &fdr);
		struct timeval tv = {0, 50000};	// 50ms
		err = select(0, &fdr, NULL, NULL, &tv);
		if ( err < 0  )
			break;
		if ( err > 0 && FD_ISSET(sclient, &fdr) )
#endif/*USE_SELECT*/
		{
			err = recv(sclient, (char*)buf, buf_size, 0);
			if ( err < 0 ) {
				perror("recv");
				return -7;
			} else if ( 0 == err ) {
				printf("client close connection.\n");
				return 0;
			}
			stat_bytes += err;
		}
		// Stat.
		DWORD time_now = timeGetTime();
		DWORD time_escape = time_now - stat_last_time;
		if ( time_escape >= 1000 ) {
			double speed_mb = (stat_bytes * 1000.0) / (time_escape * 1024.0 * 1024.0);
			printf("recv %.1fKB in %.1fs, speed is %.1fMB/s\n", stat_bytes / 1024.0, time_escape / 1000.0, speed_mb);
			stat_last_time = time_now;
			stat_bytes = 0;
		}
	}
	delete []buf;
	return 0;
}

// testnet tcp send [<remote ip> <remote port> [<buffer size>]]
int tcp_send(int argc, char* argv[])
{
	printf("tcp_send(client):\n");
	unsigned long ip = inet_addr("127.0.0.1");
	if (argc > 1 ) { 
		ip = inet_addr(argv[1]);
		if ( 0 == ip ) {
			fprintf(stderr, "invalid IP address \"%s\"\n", argv[1]);
			return -1;
		}
	}
	int port = 3000;
	if ( argc > 2 ) {
		if ( sscanf(argv[2], "%d", &port) != 1 ) {
			fprintf(stderr, "invalid tcp port \"%s\"\n", argv[2]);
			return -2;
		}
	}
	int buf_size = 1024 * 32;
	if ( argc > 3 ) {
		if ( sscanf(argv[3], "%d", &buf_size) != 1 ) {
			fprintf(stderr, "invalid buffer size \"%s\"\n", argv[3]);
			return -3;
		}
	}
	LPBYTE buf = new BYTE[buf_size];
	if ( NULL == buf ) {
		perror("allocate buffer");
		return -4;
	}
	for ( int i = 0; i < buf_size; i++ )
		buf[i] = (BYTE)i;
	printf("packet size %d\n", buf_size);
	SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if ( INVALID_SOCKET == s ) {
		perror("creat TCP socket");
		return -5;
	}
	int send_buf_size = buf_size * 2 + 1024 * 32;
	int err = setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char*)&send_buf_size, sizeof(send_buf_size));
	if ( err < 0 ) {
		perror("set socket send buffer size");
		return -6;
	}
	// connect to remote
	struct sockaddr_in sa;
	memset(&sa, 0, sizeof(sa));
	sa.sin_family = AF_INET;
	sa.sin_addr.S_un.S_addr = ip;
	sa.sin_port = htons(port);
	err = connect(s, (struct sockaddr*)&sa, sizeof(sa));
	if ( err < 0 ) {
		perror("connect failed");
		return -6;
	}
	// send loop
	int stat_bytes = 0;
	DWORD stat_last_time = timeGetTime();
	while ( !_kbhit() ) {
#ifdef USE_SELECT
		FD_SET fdw;
		FD_ZERO(&fdw);
		FD_SET(s, &fdw);
		struct timeval tv = {0, 50000};	// 50ms
		err = select(0, NULL, &fdw, NULL, &tv);
		if ( err < 0  )
			break;
		if ( err > 0 && FD_ISSET(s, &fdw) )
#endif/*USE_SELECT*/
		{
			err = send(s, (char*)buf, buf_size, 0);
			if ( err < 0 ) {
				perror("send");
				return -7;
			}
			stat_bytes += err;
		}
		// Stat.
		DWORD time_now = timeGetTime();
		DWORD time_escape = time_now - stat_last_time;
		if ( time_escape >= 1000 ) {
			double speed_mb = (stat_bytes * 1000.0) / (time_escape * 1024.0 * 1024.0);
			printf("send %.1fKB in %.1fs, speed is %.1fMB/s\n", stat_bytes / 1024.0, time_escape / 1000.0, speed_mb);
			stat_last_time = time_now;
			stat_bytes = 0;
		}
	}
	delete []buf;
	return 0;
}

int tcp(int argc, char* argv[])
{
	printf("tcp:\n");
	++argv;
	--argc;
	if ( argc > 0 ) {
		if ( stricmp(argv[0], "--help") == 0 || stricmp(argv[0], "-h") == 0 ) {
		} else if ( stricmp(argv[0], "recv") == 0 ) {
			return tcp_recv(argc, argv);
		} else if ( stricmp(argv[0], "send") == 0 ) {
			return tcp_send(argc, argv);
		} else {
			fprintf(stderr, "invalid parameter \"%s\"!\n", argv[0]);
		}
	}
	fprintf(stderr, "testnet tcp recv [<bind port> [<buffer size>]]\n");
	fprintf(stderr, "testnet tcp send [<remote ip> <remote port> [<buffer size>]]\n");
	return 0;
}

hugeice 2012-12-15
  • 打赏
  • 举报
回复
引用 29 楼 Squall_zy 的回复:
我专门做了一下实验,现把结果给你。 UDP传输时,即使你不接收,协议栈依然要做很多工作,这是需要消耗cpu的,但是,对于开发者而言,编写的程序本身不应该占用很多cpu,否则程序肯定需要优化。 实验条件: 1、双方使用千兆网卡,网络占用接近70%,纯UDP数据传输,单个报文大小为1K。 2、双方每秒的通信量均维持在700Mbps,约87.5MB/s的数据量(比你……
另外,上面的接收端测试程序在我的电脑上(AMD A10, 4核心,3.4GHz,8G内存)不开程序CPU占用15%,开启程序后占用18% 为什么你的接收端的CPU占用率这么低!在数据量是我的10倍的情况下CPU占用率居然与我的相当!如果你也是用1K左右的UDP包的话,那么你的包速率应该是我的10倍!能否把你的代码贴出来看看? 或者你看看我的代码那里有问题,代码发在38楼,谢谢!
加载更多回复(37)

18,356

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧