请问各位大哥!indy组件通讯效率如何能提高,多谢 ( 积分: 100 )

  • 主题发起人 主题发起人 meigreat
  • 开始时间 开始时间
M

meigreat

Unregistered / Unconfirmed
GUEST, unregistred user!
最近做一个通讯类服务,但用到的Indy组件不太训练!请各位大哥多指教
 
哦,没有人回答呀,自已先顶一下
 
INDY由于是线程模式,所以如果是连接数较少(50以内),它的性能还是不错的,如果比较多的话,还是不要用INDY的好,系统性能下降的很快,而且一不小心就容易出错,你的线程使用能力要跟得上。
 
去网站下载demo,一看就明白了。
我用了两年多了,感觉不错。
 
guanyueguan 说得很多,我们经常要用到几百个连接,但是通讯量都不是很大,要求及时性很高,所以请教一下有什么好办法??
看了一下那个IOCP的帖子,是不是这个东东能解决这个问题呢??
谢谢
 
如果你熟悉IOCP最好,但我對那塊不是很熟,寫的IOCP程序經常出錯,所以這點我是幫不上你。
我用INDY做過400-500個連接,發現達到這個線程數對服務器是一個較重的負擔,所以不用了,而且我發現INDY有個不好的地方,你不手動檢測斷了線的連接的話,總會或多或少的有線程沒釋放,造成內存洩漏。
我覺得如果是500以內的連接完全可以用異步+工作線程池的方式做,但用IOCP更好,我不是很熟,所以不用,省得出麻煩。
 
INDY的具体性能我不清楚 那东西我就是觉的好用 做起东西来方便
但是有听一些富翁说当用到的时候说那东西会内存泄露掉 效率好象不是很高~
 
自己使用API函数写吧。又不是很难!
 
indy对连接断开不能自动判断 ,用完成端口的话可以得到 FD_ClOSE的消息,而且indy对大量用户连接负担太大,TCP还有就是自动帮你分包和组包对应用程序的设计的时候需要考虑好
 
谢谢各位大哥回贴,近日翻了很多贴子,有很多人认为Iocp好,也有人认为它也有不足的地方,但在大富翁里面只有很少遍谈到了这些,所以我在CSDN上找到了一个示例:

1. stdafx.h 中的#include <windows.h>下添加
#include <stdio.h>
#include <time.h>
#include <assert.h>
#include &quot;server.h&quot;
// TODO: reference additional headers your program requires here
// WinSock 2.2

#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment(lib,&quot;ws2_32.lib&quot;)

#define WM_SOCKET WM_USER + 1214
#define DATA_BUFSIZE 4096


// 重叠I/O 结构体
typedef struct tagPerHandleData
{
SOCKET Socket;
} PER_HANDLE_DATA, * LPPER_HANDLE_DATA;

typedef struct tagPerIoOperationData
{
OVERLAPPED Overlapped;
WSABUF DataBuf;
CHAR Buffer[DATA_BUFSIZE];
BOOL OperationType;
} PER_IO_OPERATION_DATA, * LPPER_IO_OPERATION_DATA;

typedef struct tagPDATA
{
SOCKET Socket; // 头
CHAR Buffer[DATA_BUFSIZE]; // 数据包
DWORD BytesTransferred; // 数据包大小
} PDATA, * LPPDATA;

#define RECV_POSTED 0
#define SEND_POSTED 1
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.


2.stdafx.cpp 中内容不变


3.LoveServer.cpp中

// LoveServer.cpp : Defines the entry point for the application.
//

#include &quot;stdafx.h&quot;

////////////////////////////////////////////////////
HINSTANCE hInst;
HWND hWnd;

#define WINDOWS_TITLE &quot;PCP Server&quot;
#define WINDOWS_CLASS &quot;PCP_SERVER_EXE_WIN_INC&quot;

BOOL InitWindows(HINSTANCE hInstance, int nCmdShow); // 初始化窗体
LRESULT CALLBACK WinProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam); // 消息处理函数
BOOL RegWriteString(HKEY m_hKey, LPCTSTR lpSubKey, LPCTSTR lpValueName, LPCTSTR lpVal);
///////////////////////////////////////////////////

int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// TODO: Place code here.

#ifdef _DEBUG
AllocConsole();
freopen(&quot;CONOUT$&quot;, &quot;a&quot;, stdout);
#endif

char szCurProPath[MAX_PATH];

// get current path
memset(szCurProPath,0,MAX_PATH);
GetModuleFileName(NULL,szCurProPath,MAX_PATH);
char *pos=strrchr(szCurProPath,'//');
szCurProPath[pos-szCurProPath+1]=0;
strcat(szCurProPath,&quot;pcpServer.exe&quot;);

//RegWriteString(HKEY_LOCAL_MACHINE,&quot;SOFTWARE//Microsoft//Windows//CurrentVersion//Run&quot;,&quot;pcpServer&quot;,szCurProPath);



// 加载winsock.dll
WSADATA wsa;
WSAStartup( MAKEWORD(2,2), &amp;wsa );

// 创建窗体,并隐藏
// if (!InitWindows(hInstance, SW_HIDE))
// return 0;

printf(&quot;Server is Run.../n&quot;);
StartServer(8099);


// MSG msg;
// while(GetMessage(&amp;msg, NULL, 0, 0))
// {
// TranslateMessage(&amp;msg);
// DispatchMessage(&amp;msg);
// }

// return msg.wParam;

// 卸载winsock.dll
WSACleanup();

return 0;
}




// 初始化窗体
BOOL InitWindows(HINSTANCE hInstance, int nCmdShow)
{
hInst=hInstance;
WNDCLASS wc;
wc.style = NULL;
wc.lpfnWndProc = (WNDPROC)WinProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(hInstance,MAKEINTRESOURCE(IDI_ICON1));
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = WINDOWS_CLASS;
RegisterClass(&amp;wc);

hWnd = CreateWindow(WINDOWS_CLASS,
WINDOWS_TITLE,
WS_OVERLAPPEDWINDOW,
0,
0,
300,
300,
NULL,NULL,hInstance,NULL);

if( !hWnd ) return FALSE;

ShowWindow(hWnd,nCmdShow);
UpdateWindow(hWnd);

return TRUE;
}





//---------------------------------------------------------------
//-- 消息函数
//---------------------------------------------------------------
LRESULT CALLBACK WinProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
{
switch(message)
{
case WM_CREATE:


break;
case WM_DESTROY: //程序是否存在



PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}


/********************************************************************

函数名: RegWriteString
参 数:
写入注册表RGB_SZ值
m_hKey - HKEY_XXXX_XXXX
lpSubKey - xxx/xxx/xxx
lpValueName
lpVal

返回值: TRUE时成功,返回FALSE时失败
********************************************************************/
BOOL RegWriteString(HKEY m_hKey, LPCTSTR lpSubKey, LPCTSTR lpValueName, LPCTSTR lpVal)
{
HKEY hKey;
long lReturn;

lReturn = RegOpenKeyEx(m_hKey,lpSubKey,0L,KEY_ALL_ACCESS,&amp;hKey);

if(lReturn!=ERROR_SUCCESS)
{
DWORD dw;
lReturn=RegCreateKeyEx(m_hKey,lpSubKey,0L,NULL,REG_OPTION_VOLATILE,KEY_ALL_ACCESS,NULL,&amp;hKey,&amp;dw);

if(lReturn!=ERROR_SUCCESS)
{
return FALSE;
}
}

lReturn=RegSetValueEx(hKey,lpValueName,0L,REG_SZ,(const BYTE *) lpVal,strlen(lpVal)+1);

if(lReturn==ERROR_SUCCESS)
return TRUE;

return FALSE;
}

4.server.h中

// server.h: interface for the server class.
//
//////////////////////////////////////////////////////////////////////
#ifndef _SERVER_H
#define _SERVER_H

#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>

#define WELCOME_INFO &quot;Welcome to China Honker's PCP! [1.0.1]/r/n/r/n&quot;

typedef struct tagUserInfo
{
// 机器信息
SOCKET sock;
char UserName[50];

struct tagUserInfo* next; //链表指针

}USERINFO, *PUSERINFO;

typedef struct tagUserItem
{
char UserName[20];
}USERITEM, *PUSERITEM;

extern bool StartServer(unsigned int port); // 启动服务
extern void StopServer(void); // 停止服务

DWORD WINAPI ServerThreadProc(LPVOID pParam);
DWORD WINAPI ServerWorkerThread(LPVOID CompletionPortID);
DWORD WINAPI Ser_RecvProc(LPVOID pParam);

void OnBroadcast(char *Buffer, int len); // 广播

////////////////////////////////////////////////////////////////////
// 链表函数

BOOL AddNode(SOCKET sock, char UserName[20]);
extern void ClearLogin(void);
extern void Print();
BOOL FindNode(char *CorName);
BOOL FindNode(SOCKET sock);
void DeleteNode(SOCKET sock);
char* GetUserName(SOCKET sock);

#endif

5.server.cpp中

#include &quot;stdafx.h&quot;
#include &quot;server.h&quot;

static SOCKET ServerListen;

//////////////////////////////////////////////////////////////////////////
// 登录链表控制指针

USERINFO *user_head = NULL,*user_end = NULL;
DWORD user_num = 0;

/***********************************************************************

服务控制模块 ( Server Control Module )

************************************************************************/

// 1. 启动网络服务
bool StartServer(unsigned int port)
{
// CreateThread( NULL, 0, ServerThreadProc, (LPVOID)port, 0, NULL );
ServerThreadProc((LPVOID)port);
return TRUE;
}

// 2. 停止网络服务
void StopServer(void)
{
if (ServerListen != INVALID_SOCKET )
closesocket(ServerListen);
}

///////////////////////////////////////////////////////////////////////////////////
///////////////////////// ///////////////////////////////////
//////////////////////// Net Server ///////////////////////////////////
/////////////////////// ///////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

//
// 网络处理函数
//
DWORD WINAPI ServerThreadProc(LPVOID pParam)
{
unsigned int port = (unsigned int)pParam;

HANDLE hCompletionPort; // 完成端口句柄
SYSTEM_INFO SystemInfo; // 系统信息
DWORD dwThreadID; // 线程ID
SOCKET Accept; // 接受套接字
LPPER_HANDLE_DATA PerHandleData; //Per句柄信息
LPPER_IO_OPERATION_DATA PerIoData;

DWORD dwFlag,RecvBytes;
struct sockaddr_in InternetAddr,addr; // 地址结构体


/***********************************
CreateIoCompletionPort(
HANDLE FileHandle, //指定一个要同完成端口关联在一起的套接字句柄
HANDLE ExistingCompletionPort, //指定一个现有的完成端口
DWORD CompletionKey, //指定要与某个特定的套接字句柄关联在一起的&quot;单句柄数据&quot;
DWORD NumberOfConcurrentThreads //并发线程数量
);
该函数有两个明显有别的目的:
1.创建一个完成端口对象
2.将一个句柄同完成端口关联到一起

该处用于创建一个完成端口,最开始创建一个完成端口时候,前三个参数将被忽略.第4个参数为0表示每个处理器一次只允许执行一个工作者线程
该处语句的作用是返回一个句柄,在为完成端口分配了一个套接字句柄后,用来对那个端口进行标定(引用)
***********************************/

/******1.创建一个完成端口**********/
hCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0); // 创建I/O完成端口
if (hCompletionPort == NULL)
{
MessageBox(NULL,&quot;CreateIoCompletionPort failed!&quot;,&quot;NetFileServerThreadProc&quot;,0);
return 0;
}


/******2.判断系统内的处理器个数*********/
GetSystemInfo( &amp;SystemInfo ); // 获得处理器的个数
for( DWORD i = 0; i < SystemInfo.dwNumberOfProcessors; i++ ) // 创建处理器个数相同的工作者线程
{
HANDLE hThread;
/******3.创建一个服务器工作者线程, 并且传递完成端口给它********/
hThread = CreateThread( NULL, 0, ServerWorkerThread, hCompletionPort, 0, &amp;dwThreadID );
if (hThread == NULL)
{
MessageBox(NULL, &quot;CreateThread() failed!&quot;, &quot;NetFileServerThreadProc&quot;, 0);
CloseHandle(hCompletionPort);
return 0;
}
CloseHandle( hThread ); // 关闭线程句柄
}


/*******4.创建监听套接字********/
ServerListen = WSASocket( AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED );
if (ServerListen == INVALID_SOCKET)
{
MessageBox(NULL, &quot;WSASocket() failed!&quot;, &quot;NetFileServerThreadProc&quot;, 0);
CloseHandle(hCompletionPort);
return 0;
}


/*******5.绑定端口**********/
InternetAddr.sin_family = AF_INET;
InternetAddr.sin_addr.s_addr = htonl( INADDR_ANY );
InternetAddr.sin_port = htons( port );
if ( bind( ServerListen, (SOCKADDR *)&amp;InternetAddr, sizeof(InternetAddr) ) == SOCKET_ERROR ) // 绑定IP和Port
{
MessageBox(NULL, &quot;bind() failed!&quot;,&quot;NetFileServerProc&quot;,0);
closesocket(ServerListen);
CloseHandle(hCompletionPort);
return 0;
}


/*******6.准备监听***********/
if (listen( ServerListen, 5 ) == SOCKET_ERROR)// 准备监听
{
MessageBox(NULL, &quot;listen() failed!&quot;, &quot;NetFileServerProc&quot;, 0);
closesocket(ServerListen);
CloseHandle(hCompletionPort);
return 0;
}

while(TRUE)
{
/******7.接受进入的连接请求**************/
// 接受连接并且分配到完成端口上
if ((Accept = WSAAccept(ServerListen, (SOCKADDR *)&amp;addr, NULL, NULL, 0 )) == SOCKET_ERROR)
{
break;
}


/******8.创建一个数据结构,用于容纳&quot;单句柄数据&quot;,同时在结构中存入接受的套接字句柄************/
// 创建per-handle数据(单句柄数据)信息结构到socket上
PerHandleData = (LPPER_HANDLE_DATA) GlobalAlloc( GPTR, sizeof(PER_HANDLE_DATA) );

if (PerHandleData == NULL)
{
MessageBox(NULL, &quot;GlobalAlloc() failed!&quot;,&quot;NetFileServerProc&quot;,0);
break;
}
PerHandleData->Socket = Accept;


/******9.将自accept返回的新套接字句柄同完成端口关联到一起,同时将单句柄数据结构传递给CreateIoCompletionPort****/
// 完成端口接受Socket
if (CreateIoCompletionPort( (HANDLE)Accept, hCompletionPort, (unsigned long)PerHandleData, 0 ) == NULL)
{
MessageBox(NULL, &quot;CreateIoCompletionPort2() failed!&quot;,&quot;NetFileServerProc&quot;,0);
break;
}


/******10.启动I/O进程,抛出一个或多个WSASend() 或WSARecv() 调用请求******/
// 在Socket上使用重叠I/O

// 投递一次接收,由于接收都需要使用这个函数来投递一个接收的准备
PerIoData = (LPPER_IO_OPERATION_DATA) GlobalAlloc( GPTR, sizeof(PER_IO_OPERATION_DATA) );
if (PerIoData == NULL)
{
MessageBox(NULL, &quot;GlobalAlloc() failed!&quot;,&quot;NetFileServerProc&quot;,0);
return 0;
}

ZeroMemory(&amp;(PerIoData->Overlapped), sizeof(OVERLAPPED));
PerIoData->OperationType = RECV_POSTED;
PerIoData->DataBuf.len = DATA_BUFSIZE;
PerIoData->DataBuf.buf = PerIoData->Buffer;

dwFlag = 0;

if (WSARecv( Accept, &amp;(PerIoData->DataBuf), 1, &amp;RecvBytes, &amp;dwFlag,
&amp;(PerIoData->Overlapped), NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() != ERROR_IO_PENDING)
{
MessageBox(NULL, &quot;WSARecv() failed!&quot;, &quot;NetFileServerProc&quot;,0);
return 0;
}
}
}

return 0;
}

////////////////////////////////需要的话修改这里以下/////////////////////////////
//
// 服务工作者线程
//
DWORD WINAPI ServerWorkerThread(LPVOID CompletionPortID)
{
// 获得完成端口
HANDLE CompletionPort = (HANDLE) CompletionPortID;

DWORD BytesTransferred;
LPPER_HANDLE_DATA PerHandleData;
LPPER_IO_OPERATION_DATA PerIoData;
DWORD SendBytes=0, RecvBytes;
DWORD Flags;

while(TRUE)
{
/************************************
将套接字句柄与一个完成端口关联在一起后,便可以以套接字为基础,投递发送与接受请求,开始对I/O请求处理
WINBASEAPI
BOOL
WINAPI
GetQueuedCompletionStatus(
HANDLE CompletionPort, //要在上面等待的完成端口
LPDWORD lpNumberOfBytesTransferred, //完成了一次I/O操作后(如WSASend或WSARecv),接收实际传输的字节数
LPDWORD lpCompletionKey, //单句柄数据
LPOVERLAPPED *lpOverlapped, //接收完成的I/O操作的重叠结果
DWORD dwMilliseconds //INFINITE,调用无休止的等待下去
);
************************************/
// 完成端口来消息了
if (GetQueuedCompletionStatus( CompletionPort, &amp;BytesTransferred,
(LPDWORD)&amp;PerHandleData, (LPOVERLAPPED *)&amp;PerIoData, INFINITE) == 0)
{
if (GetLastError() == 64) // 异常中止通讯, 强行关闭此连接
{
char buffer[100];
sprintf(buffer, &quot;%s 已经离开了!/r/n&quot;, GetUserName(PerHandleData->Socket));
OnBroadcast(buffer, strlen(buffer)+1);

DeleteNode(PerHandleData->Socket); // 移除当前用户的信息
Print();

closesocket(PerHandleData->Socket);
GlobalFree( PerHandleData );
GlobalFree( PerIoData );

continue;
}
else
{
MessageBox(NULL, &quot;GetQueuedCompletionStatus() failed!&quot;,&quot;NetFileServerWorkerThread&quot;,0);
return 0;
}
}


/******检查在套接字上是否有错误发生,如果有,则关闭套接字,清空在该套接字上的PerHandleData,PerIoData******/
// 请求退出
if (BytesTransferred == 0 &amp;&amp;
(PerIoData->OperationType == RECV_POSTED ||
PerIoData->OperationType == SEND_POSTED))
{
char buffer[100];
sprintf(buffer, &quot;%s 已经离开了!/r/n&quot;, GetUserName(PerHandleData->Socket));
OnBroadcast(buffer, strlen(buffer)+1);

DeleteNode(PerHandleData->Socket); // 移除当前用户的信息
Print();

closesocket(PerHandleData->Socket);
GlobalFree( PerHandleData );
GlobalFree( PerIoData );
continue;
}


// 接收消息
if (PerIoData->OperationType == RECV_POSTED)
{
PDATA *pData = new PDATA;
if (pData == NULL) continue;

// 填充数据
pData->Socket = PerHandleData->Socket;
pData->BytesTransferred = BytesTransferred;
memcpy(pData->Buffer, PerIoData->Buffer, DATA_BUFSIZE);;

CreateThread(NULL, 0, Ser_RecvProc, (LPVOID)pData, 0, NULL );
}


// 发送消息
if (PerIoData->OperationType == SEND_POSTED)
{

}


// 抛出等待接受下一次重叠请求
Flags = 0;
ZeroMemory(&amp;(PerIoData->Overlapped), sizeof(OVERLAPPED));

PerIoData->DataBuf.len = DATA_BUFSIZE;
PerIoData->DataBuf.buf = PerIoData->Buffer;
PerIoData->OperationType = RECV_POSTED;

WSARecv(PerHandleData->Socket,
&amp;(PerIoData->DataBuf), 1, &amp;RecvBytes,
&amp;Flags, &amp;(PerIoData->Overlapped), NULL);
}

return 0;
}



// 接受消息处理线程
DWORD WINAPI Ser_RecvProc(LPVOID pParam)
{
LPPDATA lpData = (LPPDATA) pParam;
lpData->Buffer[lpData->BytesTransferred] = '/0';

// 3D 27 C2 E2 43 77 37 7B DD 90 79 62 A5 3E 13 EB (&quot;pcp&quot;的MD5串值)

if ( lpData->Buffer[0] == 101 &amp;&amp;
lpData->Buffer[1] == -64 &amp;&amp;
lpData->Buffer[2] == -3 &amp;&amp;
lpData->Buffer[3] == 49 )
{
if( AddNode(lpData->Socket, &amp;lpData->Buffer[4]) )
{
send(lpData->Socket, &quot;100 Login Success&quot;, 18, 0);

// 发送欢迎消息(个人)
char WelcomeBuf[1024], INIPath[MAX_PATH];

// 获得当前目录
memset(INIPath,0,MAX_PATH);
GetModuleFileName(NULL,INIPath,MAX_PATH);
char *pos=strrchr(INIPath,'//');
INIPath[pos-INIPath+1]=0;
strcat(INIPath, &quot;pcpServer.ini&quot;);

GetPrivateProfileString(&quot;config&quot;,&quot;welcome&quot;,WELCOME_INFO, WelcomeBuf, 1024, INIPath);
send(lpData->Socket, WelcomeBuf, strlen(WelcomeBuf)+1, 0);

// 发送欢迎消息(全部)
char buffer[100];
sprintf(buffer, &quot;欢迎 %s 加入我们!/r/n/r/n&quot;, &amp;lpData->Buffer[4]);
OnBroadcast(buffer, strlen(buffer)+1);
}
else
send(lpData->Socket, &quot;101 Login Failed&quot;, 17, 0);
}
else if ( strcmp(lpData->Buffer, &quot;1 LIST&quot;) == 0 ) // 获得在线用户列表
{
// 创建用户列表缓冲
char pInfo[1024];

USERINFO* temp;
temp = user_head;

while( temp != NULL )
{
send(lpData->Socket, temp->UserName, strlen(temp->UserName)+1, 0);

temp = temp->next;
}

sprintf(pInfo, &quot;在线总人数: %d&quot;, user_num);

send(lpData->Socket, pInfo, strlen(pInfo)+1, 0);
}
else if ( lpData->Buffer[0] == '2' &amp;&amp;
lpData->Buffer[1] == ' ' &amp;&amp;
lpData->Buffer[2] == 'B' &amp;&amp;
lpData->Buffer[3] == 'O' ) // 广播消息
{
char Buffer[4096];
char date[20], time[20];

sprintf(Buffer, &quot;%s (%s %s)/r/n%s/r/n&quot;, GetUserName(lpData->Socket), _strdate(date), _strtime(time), &amp;lpData->Buffer[4]);

printf(&quot;Recv Message: %s/n&quot;, Buffer);
OnBroadcast(Buffer, strlen(Buffer)+1);
}

delete lpData;

return 0;
}



//////////////////////////这里以下不需要修改////////////////////////////////
// 添加帐号到登录链表中
BOOL AddNode(SOCKET sock, char* UserName)
{
if ( FindNode(UserName) ) return FALSE; // 重名登录, 不允许

printf(&quot;Add User: %s./n&quot;, UserName);

// 申请结点
USERINFO* node;
node = new USERINFO;
if (node == NULL)
return FALSE;

// 写入信息
node->sock = sock;
memcpy(node->UserName, UserName, 20);
node->next = NULL; // 结尾为NULL

if ( user_head == NULL ) // 新建头元素
{
user_head = node;
user_end = node;
}
else // 接上.
{
user_end->next = node;
user_end = node;
}

user_num++;

Print();

return TRUE;
}


// 添空登录链表
void ClearUser(void)
{
USERINFO *temp,*p;
p = user_head;

while( p != NULL )
{
temp = p;
p = p->next;

delete temp;
}

user_head = NULL;
user_end = NULL;
user_num = 0;
}


void Print()
{
USERINFO* temp;
temp = user_head;

printf(&quot;/n---------------/n&quot;);
printf(&quot;Print Start.../n&quot;);
int index=0;
while( temp != NULL )
{
printf(&quot;%d: %X/t%s/n&quot;, index++, temp->sock, temp->UserName);
temp = temp->next;
}

printf(&quot;---------------/n&quot;);
}


char* GetUserName(SOCKET sock)
{
USERINFO* temp;
temp = user_head;

while( temp != NULL )
{
if (sock == temp->sock)
return temp->UserName;

temp = temp->next;
}

return NULL;
}

BOOL FindNode(char *UserName)
{
USERINFO* temp;
temp = user_head;

while( temp != NULL )
{
if (strcmp(UserName, temp->UserName) == 0)
return TRUE;

temp = temp->next;
}

return FALSE;
}

BOOL FindNode(SOCKET sock)
{
USERINFO* temp;
temp = user_head;

while( temp != NULL )
{
if (sock == temp->sock)
return TRUE;

temp = temp->next;
}

return FALSE;
}

void DeleteNode(SOCKET sock)
{
USERINFO *temp, *p;
temp = user_head;

if (temp == NULL) return;

// 1. 删除链表头
if (user_head->sock == sock)
{
user_head = user_head->next;

delete temp;
user_num--;
return;
}

// 2. 任意一链表结点
while( temp != NULL )
{
if (temp->next->sock == sock) // 下一次就是要删除的
{
p = temp->next; // p为待删除的节点
temp->next = p->next; // 断开p节点, 首尾相连

delete p;
user_num--;
return;
}
temp = temp->next;
}
}



void OnBroadcast(char *Buffer, int len)
{
USERINFO* temp;
temp = user_head;

printf(&quot;/n Serach Client.../n&quot;);
while( temp != NULL )
{
if ( temp->sock != INVALID_SOCKET )
{
printf(&quot;/tSend %s./n&quot;, temp->UserName);
send(temp->sock, Buffer, len, 0);
}

temp = temp->next;
}
printf(&quot; Send OK!/n/n&quot;);
}

Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1473498
请大家多看一下,谢谢
 
长时间没人跟贴了,还是谢谢大家的回答!我找到了一些解决方法,不能已附件的形式贴出来,不能不说是遗憾了! 分的分数很少,了表心意;呵呵
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
D
回复
0
查看
2K
DelphiTeacher的专栏
D
后退
顶部