2013-06-04 2 views
0

Я пишу сетевую игру на C++, используя Winsock UDP сокеты, и у меня есть проблема, что каждый раз, когда вызывается sendto(), она увеличивает использование памяти необратимым образом , Самое странное, что появляется только на клиенте, на сервере нет проблем, хотя он использует почти идентичный сетевой код.C/C++ Winsock UDP - sendto() на клиенте вызывает утечку памяти

Вот конструктор класса клиента, где создается соединение (я не могу показать весь код, потому что это намного больше, и это не проект с открытым исходным кодом):

Client(){ 
nospawn = true; 
status = 0; 
hThread = 0; 
firstrs = NULL; 
lastrs = NULL; 

if (WSAStartup(0x0101, &rdata) != 0) exit(WSAGetLastError()); 
sd = socket(AF_INET, SOCK_DGRAM, 0); 
if (sd == INVALID_SOCKET) exit(WSAGetLastError()); 

gethostname(host_name, sizeof(host_name)); 
hp = gethostbyname(host_name); 

FILE * file; 
BYTE * data; 

fopen("config.txt", "rb"); 
data= (BYTE*)malloc (15); 
fread(data, 15, 1, file); 
fclose(file); 
memset((void *)&server, '\0', sizeof(struct sockaddr_in)); 
server.sin_family = AF_INET; 
server.sin_port = htons(8334); 
server.sin_addr.S_un.S_un_b.s_b1 
    = (unsigned char)(((int)data[0]-48)*100+((int)data[1]-48)*10+(int)data[2]-48); 
server.sin_addr.S_un.S_un_b.s_b2 
    = (unsigned char)(((int)data[4]-48)*100+((int)data[5]-48)*10+(int)data[6]-48); 
server.sin_addr.S_un.S_un_b.s_b3 
    = (unsigned char)(((int)data[8]-48)*100+((int)data[9]-48)*10+(int)data[10]-48); 
server.sin_addr.S_un.S_un_b.s_b4 
    = (unsigned char)(((int)data[12]-48)*100+((int)data[13]-48)*10+(int)data[14]-48); 

/* Clear out client struct */ 
memset((void *)&client, '\0', sizeof(struct sockaddr_in)); 
client.sin_family = AF_INET; 
client.sin_port = htons(0); 
client.sin_addr.S_un.S_un_b.s_b1 = hp->h_addr_list[0][0]; 
client.sin_addr.S_un.S_un_b.s_b2 = hp->h_addr_list[0][1]; 
client.sin_addr.S_un.S_un_b.s_b3 = hp->h_addr_list[0][2]; 
client.sin_addr.S_un.S_un_b.s_b4 = hp->h_addr_list[0][3]; 
server_length = sizeof(struct sockaddr_in); 

if (bind(sd, (struct sockaddr *)&client, sizeof(struct sockaddr_in))==-1){ 
    closesocket(sd); 
    WSACleanup(); 
    exit(WSAGetLastError()); 
}; 
}` 

И функция, которая отправляет данные на сервер:

void sendCRequest(){ 
int sum = 0; 
unsigned char c1,c2,c3,c4; 

if (ludzie[0].ster[S_RIGHT]) sum+=1; 
if (ludzie[0].ster[S_LEFT]) sum+=2; 
if (ludzie[0].ster[S_UP]) sum+=4; 
if (ludzie[0].ster[S_DOWN]) sum+=8; 
if (ludzie[0].ster[S_RUN]) sum+=16; 
if (ludzie[0].ster[S_ENTER]) sum+=32; 
if (ludzie[0].ster[S_SHOT]) sum+=64; 
if (ludzie[0].ster[S_RELOAD]) sum+=128; 

if (ludzie[0].ster[S_SHOT]){ 
    float depth; 
    GLdouble modelMatrix [16]; 
    GLdouble projMatrix [16]; 
    GLdouble dx,dy,dz; 
    GLint viewport [4]; 

    glGetDoublev(GL_MODELVIEW_MATRIX,modelMatrix); 
    glGetDoublev(GL_PROJECTION_MATRIX,projMatrix); 
    glGetIntegerv(GL_VIEWPORT,viewport); 
    glReadPixels(mx, screendy*2-my, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth); 
    gluUnProject(mx,screendy*2-my,depth,modelMatrix,projMatrix,viewport,&dx,&dy,&dz); 

    //x 
    floatEnc(dx,&c1,&c2,&c3,&c4); 
    data[16]=c1; data[17]=c2; data[18]=c3; data[19]=c4; 
    //y 
    floatEnc(dy,&c1,&c2,&c3,&c4); 
    data[20]=c1; data[21]=c2; data[22]=c3; data[23]=c4; 
    //z 
    floatEnc(dz,&c1,&c2,&c3,&c4); 
    data[24]=c1; data[25]=c2; data[26]=c3; data[27]=c4; 
} 

data[0] = 'C'; 
for (int i=1;i<9;i++) data[i]=auth[i-1]; 
data[10] = (char)sum; 
data[11]=ludzie[0].ster[S_SPACE]?'1':'0'; 
floatEnc(ludzie[0].r,&c1,&c2,&c3,&c4); 
data[12]=c1; data[13]=c2; data[14]=c3; data[15]=c4; 
sendto(sd, data, RQBUFFER, 0, (struct sockaddr *)&server, server_length); 
} 

Если есть все, кроме SendTo(), нет утечки памяти, так что остальная часть кода не является проблемой. Эти вызовы OpenGL и floatEnc (он кодирует float до 4 байтов) также не важны, без sendto() все работает нормально. Существуют ли какие-либо возможные исправления, кроме использования Winsock/UDP или уничтожения и создания сокета снова каждый раз, когда использование памяти слишком велико?

+0

Я полагаю, что после того, как сервер sendto отправит что-то обратно, и клиент обрабатывает данные? Это может быть проблема? И насколько велика утечка? Что такое определение 'data' и' RQBUFFER'? – Inspired

+0

RQBUFFER теперь 32, данные: данные char [RQBUFFER]; Я тестировал его в ситуации, когда сервер был отключен (ответов не получено), и он игнорировался на клиенте - ничего не меняется. – user1262737

+0

При запуске отладки Debug в отладчике попробуйте использовать [Visual Leak Detector] (https://vld.codeplex.com/) - он покажет вам, какая память просочилась, и где в вашем коде выделяется эта память. Это должно помочь выявить проблему. – icabod

ответ

0

У вас есть утечка памяти в Client(). Вы вызываете malloc, но не вызываете free, чтобы освободить память. Я предлагаю использовать std::vector для этого или, по крайней мере, new и delete. Кроме того, в коде, который вы включили в свой вопрос, нет других утечек. Я подозреваю, что у вас есть другой код в вашей программе, который делает то же самое Client() - звонки malloc без вызова free для освобождения памяти.

Что касается памяти, которая, по вашему мнению, просачивается в sendto, вы должны знать, что библиотеки Winsock выполняют множество задач в пространстве пользователя, включая выделение памяти. Вполне возможно, что библиотеки Winsock выделяют память для различных буферов и сохраняют их для будущего использования.

+0

Правильно, но Client() вызывается только один раз, поэтому даже если есть утечка, как он может увеличиваться с течением времени? Я прошу в основном об этом «много вещей в пространстве пользователя, включая выделение памяти» и о том, как их избежать ... – user1262737

+0

Сначала вы должны проверить остальную часть кода, чтобы убедиться, что _you_ не пропускает память. Если вы небрежны, чтобы сделать это в одном месте, это может произойти в другом месте. Поскольку у вас нет контроля над внутренней работой библиотеки Winsock или сторонних DLL, которые она загружает, вы не можете помешать ей выделять буферы, в которых она нуждается. –

+0

Я проверил все остальное, также таким образом: сервер закрыт (пакеты никуда не отправляются, ничего не получено/не обрабатывается, никаких других последствий, исключающих их, непосредственно вызванных sendto) с и без sendto() в конце - в первом случае память (~ 1 МБ каждые 10 секунд), во втором случае использование памяти является постоянным (очень мало изменений вверх и вниз, но не до бесконечности). Также с sendto вызывается только при нажатии какой-либо клавиши - в этом случае: увеличивается при нажатии, при увеличении не увеличивается. – user1262737