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未被释放掉。
[解决办法]