Bugs

MMORPG game develop.

可以交你。
博大精深。
re: Epoll笔记! Bugs 2008-06-24 11:08
@饭中淹
更加期待*nix下的AIO对套接字的支持。
完全就是与IOCP模式相同。
re: SGI STL的内存池 Bugs 2008-06-23 17:27
很好;)
re: Epoll笔记! Bugs 2008-06-23 10:25
/*
这种方式并不很完美,在理论上可能会长时间的阻塞在socket_send()内部,但暂没有更好的办法.*/
这种情况下,比较好的方法是为该socket关联一个写数据队列或缓冲,本次写失败之后,等待epoll的下一次写事件通知,再访问该关联数据队列,再次发送。
re: RamDisk好处! Bugs 2008-06-19 12:39
是的,挂接点的不同而已。
re: 配置文件类![未登录] Bugs 2008-05-27 10:11
@yayv
谢谢 :)
@abettor
谢谢你的建议,我又对这个部分有了一个重新的了解了。
很有趣!
re: 网络编程 心得2 Bugs 2008-04-25 11:03
这里在说说 REUSERADDR,
ACE网络编程里说过,windows 在 2000以后, REUSERADDR 标识默认为1的。

但我在2003下测试的时候:
1.如果客户端使用了绑定端口,没有设置REUSERADDR为1时,bind的时候,会返回失败,反之成功。
但成功失败都不会影响客户端调用connect,只是成功后,则使用你指定的ADDR进行connect,失败则是随机分配的PORT进行连接。

2.但设置了REUSERADDR的作用也仅仅是上面的功能。
当在客户端主动断开连接后,处于TIME_WAIT状态时,在2MSL时间里,你绑定(bind)PORT的时候,虽然不会失败,但在connect的时候,会返回WSAEADDRINUSE(10048)错误。

10048的描述是:通常每个套接字地址(协议/网络地址/端口)只允许使用一次。

这里就跟《网络编程 心得1》里说的,处于主动关闭后的Time_wait状态下,
如果设置了REUSERADDR为1时,是可以复用prot进行连接的。
网上找了很多资料,说windows平台下这里是一个bug。
在linux平台下,还没有环境做测试,有时间找个环境测试下,应该是可以复用PORT,进行连接的。

那么现在windows平台下怎么避免2MSL时间内不能连接的问题呢。
BOOL bDontLinger = FALSE;
setsockopt(s,SOL_SOCKET,SO_DONTLINGER,(const char*)&bDontLinger,sizeof(BOOL));
这样做,使主动关闭方在close后,不经历TIME_WAIT状态,也就是说这样可能会丢失数据,比如关闭四次握手最后一次ACK如果在路由中迷途,就会影响到他的重发。
但不这样,还有其他办法吗?
@christanxw 重用端口,设置过了,但在windows(只做了win测试)平台下,是没有作用的。

// 下面是测试代码,在window平台下测试过了。
// 没有linux环境,有环境的朋友可以试试。

#ifdef WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif

#pragma comment(lib, "WS2_32.lib")
#pragma warning( disable : 4996 )

#endif

#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifdef WIN32
#include <winsock2.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#endif

#ifndef WIN32
#define wsaperror perror
#else
void wsaperror(char *);
#endif

int main(int argc, char *argv[])
{
#ifdef WIN32
WSADATA wsaData;
#endif
int succeeded = 0;
struct sockaddr_in addr = {0};
int i;

// 远端地址 随便链接一个处于listen状态的
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("192.168.170.13");
addr.sin_port = htons(135);

#ifdef WIN32
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
wsaperror("WSAStartup");
exit(1);
}
#endif
while (1) {
int s = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in local_addr = {0};


#ifdef WIN32
int name_len = sizeof(local_addr);
#else
socklen_t name_len = sizeof(local_addr);
#endif

if (s < 0) {
wsaperror("socket");
break;
}

// 下面的代码,有linux环境的朋友,注释掉,不设置DontLinger试试。
//
// 如果要已经处于连接状态的soket在调用closesocket后强制关闭,不经历TIME_WAIT的过程:
BOOL bDontLinger = FALSE;
if (setsockopt(s,SOL_SOCKET,SO_DONTLINGER,(const char*)&bDontLinger,sizeof(BOOL))< 0) {
wsaperror("setsockopt");
break;
}

i = 1;
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &i, sizeof(i)) < 0) {
wsaperror("setsockopt");
break;
}


// 本地地址
local_addr.sin_family = AF_INET;
local_addr.sin_addr.s_addr = inet_addr("192.168.170.13");
local_addr.sin_port = htons(10000);

if (bind(s, (struct sockaddr *) &local_addr, sizeof(local_addr)) < 0) {
wsaperror("bind");
break;
}

if (getsockname(s, (struct sockaddr *) &local_addr, &name_len) < 0) {
break;
}

if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
//fprintf(stderr, "Local port failed: %s : %d\n", inet_ntoa(local_addr.sin_addr), ntohs(local_addr.sin_port));
wsaperror("connect");
break;
}

succeeded++;

/* shutdown(s, 2); */
#ifdef WIN32
closesocket(s);
#else
close(s);
#endif

fprintf(stderr, "%d\n", ntohs(local_addr.sin_port));
fflush(stdout);
}

fprintf(stderr, "%d connections succeeded\n", succeeded);

#ifdef WIN32
WSACleanup();
#endif
exit(1);
}

#ifdef WIN32
void wsaperror(char *str)
{
int err = WSAGetLastError();
char *errstr;

switch (err) {
case WSAEADDRINUSE:
errstr = "WSAEADDRINUSE";
break;
case WSAENOBUFS:
errstr = "WSAENOBUFS";
break;
default:
errstr = "Unknown error";
break;
}

fprintf(stderr, "%s: Error %d (%s)\n", str, err, errstr);
}
#endif
re: 网络编程 心得1 Bugs 2008-04-11 13:45
根据ACE网络编程下提到:
在winsock2已经不存在这个问题了,不知道winsock1是否有,没有机会做测试了,有机会的朋友,找个NT4环境测试下吧。
已阅
不知道,你去找找吧
有没有办法处理Linux平台的异常处理?研究一下:)
re: 想了一下,写的真好 Bugs 2008-03-30 21:49
现场看球的感觉确实不一般,有机会一定要去尝试一下。
除了原文提到的几点,还是来总结几点吧,
可能我个人比较偏好性能,c++的新特性建议不要随意使用。

1.在设计和抽象过程中,把继承的次数降到最小,避免每次构造对象时,
需要构造很多层父类中的构造函数。

2.尽量使用C风格的类型转换
float f = 3.14;
int i = (int)f;
这样与使用static_cast作用一样,性能没有什么区别,
但dynamic_cast就不一样了,效率上大大低于static_cast,
dynamic_cast可以自己使用ObjType来处理一个对象的正确的造型,
这样做,只是麻烦了点,但有了更多的灵活性,和性能。
CXxx *x = 0;
if( obj->GetType() == TYPE_XXX )
{
x = (CXxx*)obj;
}
其实只有在一般不明确类型的时候才会使用dynamic_cast进行造型的,
但在实际编程中,这样的情况很少。
我自己对异常处理的心得有下列几点,仅供参考,希望大家说说各自的意见。
1.尽量避免使用异常处理,能不能则不用,可以用C Style的Error处理方式来代替。(对于渴望性能很实用)
2.即使要使用,也一定把Scope降到最低,尽量减少多重嵌套。
3.如果整个生产系统使用了不稳定的第三方库,建议使用异常处理,毕竟服务器稳定胜于性能。
re: 如何反外挂?[未登录] Bugs 2008-03-26 15:59
天成是那个公司?有什么作品吗?
re: 如何反外挂? Bugs 2008-03-22 21:12
好的,以后想到就发点吧。