📄 multiclientserver.c
字号:
}
/*---------------------------------------------------------------------------*/
/* Compares two client info data-structures. */
/* Used by the ListFindItem function. */
/*---------------------------------------------------------------------------*/
static int CVICALLBACK CompareClientInfoPtr (void *item1, void *item2)
{
return ((*(ClientInfoPtr *) item1)->handle
- (*(ClientInfoPtr *) item2)->handle);
}
/*---------------------------------------------------------------------------*/
/* Disconnects the client identified by the info data-structure. */
/*---------------------------------------------------------------------------*/
static int Disconnect (ClientInfoPtr clientInfoPtr, int index, int removeFromList)
{
int numUIListItems;
/* Signal client's worker thread to stop. */
clientInfoPtr->stopFlag = 1;
/* Wait for client's worker thread to stop. */
CmtWaitForThreadPoolFunctionCompletion (DEFAULT_THREAD_POOL_HANDLE,
clientInfoPtr->threadFuncId, OPT_TP_PROCESS_EVENTS_WHILE_WAITING);
/* Release the client's worker thread function. */
CmtReleaseThreadPoolFunctionID (DEFAULT_THREAD_POOL_HANDLE,
clientInfoPtr->threadFuncId);
/* Disconnect the client conversation handle. */
DisconnectTCPClient (clientInfoPtr->handle);
if (removeFromList)
ListRemoveItem (gClientList, NULL, index);
/* Remove client entry from user interface and update controls. */
GetIndexFromValue (gPanel, PANEL_CLIENT_LIST, &index, (int)clientInfoPtr);
DeleteListItem (gPanel, PANEL_CLIENT_LIST, index, 1);
GetNumListItems (gPanel, PANEL_CLIENT_LIST, &numUIListItems);
SetCtrlAttribute (gPanel, PANEL_DISCONNECT, ATTR_DIMMED, numUIListItems == 0);
SetCtrlAttribute (gPanel, PANEL_SEND, ATTR_DIMMED, numUIListItems == 0);
SetCtrlAttribute (gPanel, PANEL_DATA, ATTR_DIMMED, numUIListItems == 0);
/* Dispose client information data-structure. */
free (clientInfoPtr);
return 0;
}
/*---------------------------------------------------------------------------*/
/* Disconnects the client identified by the handle. */
/*---------------------------------------------------------------------------*/
static int DisconnectClient (unsigned int handle)
{
ClientInfo clientInfo = {0};
ClientInfoPtr clientInfoPtr = &clientInfo;
int index;
/* Find the client information from TCP conversation handle. */
clientInfoPtr->handle = handle;
index = ListFindItem (gClientList, &clientInfoPtr,
FRONT_OF_LIST, CompareClientInfoPtr);
if (index > 0)
{
/* Get the stored client information and disconnect the client. */
ListGetItem (gClientList, &clientInfoPtr, index);
Disconnect (clientInfoPtr, index, 1);
}
return 0;
}
/*---------------------------------------------------------------------------*/
/* TCP callback function for the server. */
/*---------------------------------------------------------------------------*/
static int CVICALLBACK ServerCallback (unsigned int handle, int xType,
int errCode, void *cbData)
{
if (xType == TCP_CONNECT)
{
/* Connect new client. */
ConnectClient (handle);
}
else if (xType == TCP_DISCONNECT)
{
/* Client is disconnecting. Update program state. */
DisconnectClient (handle);
}
else if (xType == TCP_DATAREADY)
{
ClientInfo clientInfo = {0};
ClientInfoPtr clientInfoPtr = &clientInfo;
int index;
/* Find the client information from TCP conversation handle. */
clientInfoPtr->handle = handle;
index = ListFindItem (gClientList, &clientInfoPtr,
FRONT_OF_LIST, CompareClientInfoPtr);
if (index > 0)
{
/* Get the stored client information. */
ListGetItem (gClientList, &clientInfoPtr, index);
/*
* NOTE - Because the reading is done in the worker thread,
* this thread (the main thread) is not blocked, and will
* continue to receive TCP_DATAREADY events, until all the
* data is read. This program uses the readingData flag to
* ignore these events, until all the data is read by the
* worker thread.
*/
if (!clientInfoPtr->readingData)
{
clientInfoPtr->readingData = 1;
PostDeferredCallToThread (DeferredReceive, clientInfoPtr,
clientInfoPtr->threadId);
}
}
}
return 0;
}
/*---------------------------------------------------------------------------*/
/* Disconnects an item in the connected clients list. */
/* Used by the ListApplyToEach function. */
/*---------------------------------------------------------------------------*/
static int CVICALLBACK DisconnectClientListItem (int index, void *itemPtr,
void *data)
{
Disconnect (*(ClientInfo **) itemPtr, index, 0);
return 0;
}
/*---------------------------------------------------------------------------*/
/* Sends data to client. */
/*---------------------------------------------------------------------------*/
static void CVICALLBACK DeferredSend (void *data)
{
int tcpErr = 0;
ClientInfoPtr clientInfoPtr = (ClientInfoPtr) data;
char *dataBuf = NULL;
int dataBufSize;
/* Get the size of the data to send. */
GetCtrlAttribute (gPanel, PANEL_DATA, ATTR_STRING_TEXT_LENGTH, &dataBufSize);
if (dataBufSize > 0)
{
/* Allocate a buffer to hold the data. */
dataBuf = malloc (sizeof (char) * (++dataBufSize));
if (dataBuf)
{
/* Pointer to current data to send. */
char *currData = dataBuf;
/* Read the data from the user interface. */
GetCtrlVal (gPanel, PANEL_DATA, dataBuf);
/* Write the data in a loop, until there is no more data to send. */
while (dataBufSize > 0)
{
int bytesSent = ServerTCPWrite (clientInfoPtr->handle,
currData, dataBufSize, 0);
if (bytesSent >= 0)
{
/* Subtract number of bytes sent from amount of data left. */
dataBufSize -= bytesSent;
/* Update current data. */
currData += bytesSent;
}
else
tcpChk (bytesSent);
}
/* Free the data buffer. */
free (dataBuf);
}
}
Done:
return;
}
/*---------------------------------------------------------------------------*/
/* Receives data from client. */
/*---------------------------------------------------------------------------*/
static void CVICALLBACK DeferredReceive (void *data)
{
ClientInfoPtr clientInfoPtr = (ClientInfoPtr) data;
char dataBuf[256];
int bytesRead;
assert (clientInfoPtr->readingData == 1);
/*
* Disable library error checking as we are going to read until
* there is no more data left (read call times out).
*/
DisableBreakOnLibraryErrors ();
while (1)
{
bytesRead = ServerTCPRead (clientInfoPtr->handle,
dataBuf, sizeof (dataBuf) - 1, 100);
if (bytesRead > 0)
{
/* Update user interface with the new data. */
dataBuf [bytesRead] = '\0';
SetCtrlVal (clientInfoPtr->panel, REC_PANEL_DATA, dataBuf);
}
else
{
/* No more data to read. Update flag, and exit loop. */
clientInfoPtr->readingData = 0;
break;
}
}
/* Enable library error checking. */
EnableBreakOnLibraryErrors ();
}
/*---------------------------------------------------------------------------*/
/* Report TCP Errors. */
/*---------------------------------------------------------------------------*/
static void ReportTCPError (int error)
{
char messageBuffer[1024];
if (error < 0)
{
sprintf(messageBuffer,
"TCP library error message: %s\nSystem error message: %s",
GetTCPErrorString (error), GetTCPSystemErrorString());
MessagePopup ("Error", messageBuffer);
}
}
/*---------------------------------------------------------------------------*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -