首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C++ Builder >

winsocket 有关问题

2012-02-02 
winsocket 问题!另外请教个问题,winsocket 每次连接成功,在传输完毕后,关闭之,都会增长4K 内存。这个4K 是

winsocket 问题!
另外请教个问题,winsocket 每次连接成功,在传输完毕后,关闭之,都会增长4K 内存。
这个4K 是在传输时设置了4k 作为接收和发送包的大小。
它不断往上长,怎么释放出来。

C/C++ code
C/C++ code 
// ---------------------------------------

// ---------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "socket.h"

// ---------------------------------------
#pragma package(smart_init)

static bool ontime = false;

// ---------------------------------------
// 0、延时函数计时器回调函数
void CALLBACK OnTimer(HWND hwnd, UINT Msg, UINT idEvent, DWORD dwTime) {
    ontime = true;
}
// ---------------------------------------
// ---------------------------------------
// 1、延时函数
void Delay(int i) {
    ontime = false;
    UINT timer;
    timer = SetTimer(NULL, NULL, i, TIMERPROC(OnTimer));
    do {
        Forms::Application->ProcessMessages();
    }
    while (!ontime);
    KillTimer(NULL, timer);
}

// ---------------------------------------
// 2、连接远程主机,返回有效SOCKET
int Connect_Server(AnsiString host, u_short port) {
    int i;
    SOCKET s;
    long* p;
    hostent* phe;
    sockaddr_in sin;
    DWORD Address;
    // 初始化socket
    WSADATA wsd;
    // int err;
    // err =
    WSAStartup(MAKEWORD(2, 2), &wsd);
    sin.sin_family = AF_INET;
    sin.sin_port = htons(port);

    Address = inet_addr(host.c_str());
    if (Address == INADDR_NONE) {
        phe = gethostbyname(host.c_str());
        if (phe) {
            p = (long*)(*phe->h_addr_list);
            sin.sin_addr.s_addr = *p;
        }
    }
    else {
        i = inet_addr(host.c_str());
        if (i != -1)
            sin.sin_addr.s_addr = i;
    }

    s = socket(PF_INET, SOCK_STREAM, 0);
    if (s == INVALID_SOCKET)
        return 0;
    if (connect(s, (struct sockaddr FAR*) & sin, sizeof(sin)) == SOCKET_ERROR) {
        // int i = WSAGetLastError();
        return 0;
    }
    else {
        return s;
    }
}

// ---------------------------------------
// 3、向SOCKET写字符串
int Write_Socket(int sockfd, AnsiString s) {
    return send(sockfd, s.c_str(), s.Length(), 0);
}

// ---------------------------------------
// 4、从SOCKET中读入一个以'\0'结束的字符串
AnsiString Socket_Readln(int sockfd) {
    AnsiString str = "";
    char buf[2] = "\0";
    int n;
    n = recv(sockfd, buf, 1, 0);
    while (n > 0) {
        Forms::Application->ProcessMessages();
        buf[1] = '\0';
        str = str + buf;


        if (buf[0] == 0x10)
            break;
        n = recv(sockfd, buf, 1, 0);
    }
    return Trim(str);
}

// ---------------------------------------
// 5、动态分配端口,并与SOCKET绑定,返回该SOCKET
SOCKET BindSocket(u_short* port) {
    struct sockaddr_in server;
    int s;
    // 初始化socket
    WSADATA wsd;
    // int err;
    // err =
    WSAStartup(MAKEWORD(2, 2), &wsd);
    if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        // Socket()失败
        return 0;
    }
    for (*port = *port > STREAMPORT ? *port : STREAMPORT; *port <= 32767; (*port)++) {
        server.sin_family = AF_INET;
        server.sin_port = htons(*port);
        server.sin_addr.s_addr = INADDR_ANY;
        if (bind(s, (struct sockaddr*) & server, sizeof(server)) == 0)
            break;
    }
    // Bind()失败
    if (!s)
        return 0;

    if (listen(s, 1) != 0) {
        // Listen()失败
        return 0;
    }
    return s;
}

// ---------------------------------------
// 6、向远程主机的指定端口发送字符串
bool SendMsg(AnsiString addr, u_short port, AnsiString msg) {
    int s;
    s = Connect_Server(addr, port);
    if (s) {
        Write_Socket(s, msg);
            WSACleanup();
        closesocket(s);
        return true;
    }
    else {
        return false;
    }
}

// ---------------------------------------
// 7、向远程主机的指定端口发送数据流
bool SendStream(AnsiString addr, u_short port, TMemoryStream* Stream) {
    char buf[PACKAGESIZE];
    int block;
    SOCKET s;

    Stream->Seek(0, soFromBeginning);
    block = floor(Stream->Size / sizeof(buf));

    s = Connect_Server(addr, port);
    if (!s) {
        // 发送数据失败
        return false;
    }
    for (int i = 1; i <= block; i++) {
        Stream->Read(buf, sizeof(buf));
        Stream->Seek(i*sizeof(buf), soFromBeginning);
        if (s) {
            send(s, buf, sizeof(buf), 0);
        }
        else {
            return false;
        }
        Forms::Application->ProcessMessages();
    }
    int others = Stream->Size - (block*sizeof(buf));
    if (others > 0) {
        if (s) {
            Stream->Read(buf, others);
            send(s, buf, others, 0);
        }
        else {
            return false;
        }


    }
        WSACleanup();
    closesocket(s);
    return true;
}

// ---------------------------------------
// 8、从远程主机的指定端口接收字符串
bool RecvString(SOCKET s, AnsiString &Str) {
    char buf[2] = "\0";
    struct sockaddr_in client;
    int ns;
    int namelen;
    Cardinal pktlen;

    namelen = sizeof(client);
    if ((ns = accept(s, (struct sockaddr*) & client, &namelen)) == -1) {
        // Accept()失败
        return false;
    }
    pktlen = recv(ns, buf, 1, 0);
    while (pktlen > 0) {
        Forms::Application->ProcessMessages();
        buf[1] = '\0';
        Str = Str + buf;
        if (buf[0] == 0x01) //
            break;
        pktlen = recv(ns, buf, 1, 0);
    }

    WSACleanup();
    closesocket(s);
    return true;
}

// ---------------------------------------
// 9、从远程主机的指定端口接收数据流
bool RecvStream(SOCKET s, TMemoryStream* Stream) {
    char buf[PACKAGESIZE];
    struct sockaddr_in client;
    int ns;
    int namelen;
    int pktlen;

    namelen = sizeof(client);
    if ((ns = accept(s, (struct sockaddr*) & client, &namelen)) == -1) {
        // Accept()失败
        return false;
    }
    while (1) {
        Forms::Application->ProcessMessages();
        if ((pktlen = recv(ns, buf, sizeof(buf), 0)) < 0) {
            // 接收数据失败
            return false;
        }
        else if (pktlen == 0)
            break;
        else {
            Stream->Seek(0, soFromEnd);
            Stream->Write(buf, pktlen);
        }
    }
    Stream->Seek(0, soFromBeginning);
    WSACleanup();
    closesocket(s);

    return true;
}
// ---------------------------------------





[解决办法]
mark一下下
[解决办法]
呃,没做过,不太明白,可以不用AnsiString,用char*试试。
[解决办法]
高速socket收发,不要在循环中频繁分配和销毁内存
AnsiString 使用过程中就是不断的动态分配内存
这种方式会导致内存碎片大量出现,最终导致内存耗尽
办法就是事先分配好足够的内存,进入循环后只是使用,而不分配和销毁
自己写个内存调度程序就可以了
[解决办法]
程序当中Socket的send,TStream的write和read都有返回值,均表示发生的有效字节数,没有加以处理。

单从这个程序片段没看出来有明显的内存泄露。
[解决办法]
楼主用codeguard看看有没提示?
[解决办法]
路过学习,不给分没关系
------解决方案--------------------


struct sockaddr_in client; 是C的写法 C++里没这必要 直接sockaddr_in client即可
AnsiString类型的函数参数 改成AnsiString & 或者 LPSTR 比较好。省去AnsiString临时构造这个环节
WSAStartup 放在程序初始化中一次即可 没必要放在Connect_Server和BindSocket函数内
WSACleanup 在所有Socket关闭后 最后调用一次即可。代码中放在了closesocket之前该代码无效。
还有僵哥说的 程序当中Socket的send,TStream的write和read都有返回值,均表示发生的有效字节数,没有加以处理。

再者没有内存泄露不等于没有内存碎片。
自己创建一个堆。用完后直接释放整个堆。这样就不易产生内存碎片。

增长的4K内存应该不是你程序中的设置的char buf[PACKAGESIZE]; 是系统级为每个socket分配缓冲。释放掉socket系统应该自动回收掉,没有回收就是你socket没释放掉。你可以用netstat -a命令看下。估计能看到有很多socket未被释放掉。
[解决办法]

热点排行