📄 multiclientserver.c
字号:
/*---------------------------------------------------------------------------*/
/* */
/* FILE: MultiClientServer.c */
/* */
/* PURPOSE: This TCP server program allows multiple TCP clients to connect */
/* to it. The program allows the user to write to any of the */
/* connected clients. The program receives and displays any data */
/* sent by the clients. The program uses worker threads to manage */
/* reading and writing to each client. You can use the TCP client */
/* sample program to interact with this server. */
/* */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/* Include files */
/*---------------------------------------------------------------------------*/
#include <tcpsupp.h>
#include <ansi_c.h>
#include <utility.h>
#include <toolbox.h>
#include "MultiClientServer.h"
/*---------------------------------------------------------------------------*/
/* Macros and constants */
/*---------------------------------------------------------------------------*/
#define SERVER_PORT_NUM 10000
#define tcpChk(f) if ((tcpErr=(f))<0) {ReportTCPError(tcpErr); goto Done;} else
/*---------------------------------------------------------------------------*/
/* Type definitions */
/*---------------------------------------------------------------------------*/
typedef struct ClientInfo
{
unsigned int handle; /* TCP conversation handle */
unsigned int threadId; /* ID of worker thread */
int threadFuncId; /* ID of worker thread function */
int stopFlag; /* Flag used to stop worker thread */
char name[256]; /* Descriptive name of client connection */
int readingData; /* Indicates server is reading from client */
int panel; /* Handle of panel to display client data */
} ClientInfo, *ClientInfoPtr;
/*---------------------------------------------------------------------------*/
/* Module-globals */
/*---------------------------------------------------------------------------*/
static int gPanel = 0; /* Main user interface panel handle */
static ListType gClientList = 0; /* List of connected clients */
/*---------------------------------------------------------------------------*/
/* Internal function prototypes */
/*---------------------------------------------------------------------------*/
static int ConnectClient (unsigned int handle);
static int DisconnectClient (unsigned int handle);
static int Disconnect (ClientInfoPtr clientInfoPtr, int index, int removeFromList);
static int CVICALLBACK ClientThreadFunction (void *data);
static int CVICALLBACK CompareClientInfoPtr (void *item1, void *item2);
static int CVICALLBACK DisconnectClientListItem (int index, void *itemPtr,
void *data);
static int CVICALLBACK ServerCallback (unsigned int handle, int xType,
int errCode, void *cbData);
static void CVICALLBACK DeferredSend (void *data);
static void CVICALLBACK DeferredReceive (void *data);
static void ReportTCPError (int error);
/*---------------------------------------------------------------------------*/
/* This is the application's entry-point. */
/*---------------------------------------------------------------------------*/
int main (int argc, char *argv[])
{
int tcpErr = 0;
int unregisterServer = 0;
if (InitCVIRTE(0, argv, 0) == 0)
return -1;
/* Load user interface */
if ((gPanel = LoadPanel (0, "MultiClientServer.uir", PANEL)) < 0)
return -1;
/* Create list to manage client connections */
gClientList = ListCreate (sizeof (ClientInfoPtr));
/* Register the server */
tcpChk (RegisterTCPServer (SERVER_PORT_NUM, ServerCallback, NULL));
unregisterServer = 1;
DisplayPanel (gPanel);
RunUserInterface ();
/* Clean up */
if (gClientList)
{
ListApplyToEach (gClientList, 0, DisconnectClientListItem, 0);
ListDispose (gClientList);
}
Done:
if (unregisterServer)
UnregisterTCPServer (SERVER_PORT_NUM);
DiscardPanel (gPanel);
return 0;
}
/*---------------------------------------------------------------------------*/
/* Respond to the panel closure to quit the UI loop. */
/*---------------------------------------------------------------------------*/
int CVICALLBACK PanelCallback (int panel, int event, void *callbackData,
int eventData1, int eventData2)
{
switch (event)
{
case EVENT_CLOSE:
QuitUserInterface (0);
break;
}
return 0;
}
/*---------------------------------------------------------------------------*/
/* Send data to connected client. */
/*---------------------------------------------------------------------------*/
int CVICALLBACK SendCallback (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
ClientInfoPtr clientInfoPtr = NULL;
switch (event)
{
case EVENT_COMMIT:
/*
* Get current client from listbox, and post the call
* to its worker thread.
*/
GetCtrlVal (gPanel, PANEL_CLIENT_LIST, (int *)(&clientInfoPtr));
PostDeferredCallToThread (DeferredSend, clientInfoPtr,
clientInfoPtr->threadId);
break;
}
return 0;
}
/*---------------------------------------------------------------------------*/
/* Disconnect a client. */
/*---------------------------------------------------------------------------*/
int CVICALLBACK DisconnectCallback (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
ClientInfoPtr clientInfoPtr = NULL;
int index;
switch (event)
{
case EVENT_COMMIT:
/* Get current client from listbox. */
GetCtrlVal (gPanel, PANEL_CLIENT_LIST, (int *)&clientInfoPtr);
/* Find the index of the client in the client list. */
index = ListFindItem (gClientList, &clientInfoPtr,
FRONT_OF_LIST, CompareClientInfoPtr);
/* Disconnect the client. */
if (index > 0)
Disconnect (clientInfoPtr, index, 1);
break;
}
return 0;
}
/*---------------------------------------------------------------------------*/
/* Worker thread function for clients. */
/*---------------------------------------------------------------------------*/
static int CVICALLBACK ClientThreadFunction (void *data)
{
ClientInfoPtr clientInfoPtr = (ClientInfoPtr) data;
clientInfoPtr->threadId = CmtGetCurrentThreadID ();
/* Load a new panel for this client message. */
clientInfoPtr->panel = LoadPanel (0, "MultiClientServer.uir", REC_PANEL);
SetPanelAttribute (clientInfoPtr->panel, ATTR_CLOSE_ITEM_VISIBLE, 0);
/* Set the client's name in the panel. */
SetCtrlVal (clientInfoPtr->panel, REC_PANEL_CLIENT_NAME,
clientInfoPtr->name);
DisplayPanel (clientInfoPtr->panel);
/* Process user-interface, TCP and other system events. */
while (!clientInfoPtr->stopFlag)
{
ProcessSystemEvents ();
}
/* Discard the client panel. */
DiscardPanel (clientInfoPtr->panel);
return 0;
}
/*---------------------------------------------------------------------------*/
/* Connects the client identified by handle. */
/*---------------------------------------------------------------------------*/
static int ConnectClient (unsigned int handle)
{
int tcpErr = 0;
ClientInfoPtr clientInfoPtr = 0;
char peerName[128], peerAddress[128];
/* Create client information data-structure. */
clientInfoPtr = calloc (1, sizeof (ClientInfo));
if (clientInfoPtr == NULL)
return -1;
clientInfoPtr->handle = handle;
/* Get descriptive name for client. */
tcpChk (GetTCPPeerName (handle, peerName, sizeof (peerName)));
tcpChk (GetTCPPeerAddr (handle, peerAddress, sizeof (peerAddress)));
sprintf (clientInfoPtr->name, "Client name: %s, address: %s",
peerName, peerAddress);
/* Create worker thread for this client. */
CmtScheduleThreadPoolFunction (DEFAULT_THREAD_POOL_HANDLE,
ClientThreadFunction, clientInfoPtr, &clientInfoPtr->threadFuncId);
/* Add the client to the list. */
ListInsertItem (gClientList, &clientInfoPtr, END_OF_LIST);
/* Add client to user interface and update disabled controls. */
InsertListItem (gPanel, PANEL_CLIENT_LIST, -1, clientInfoPtr->name,
(int)clientInfoPtr);
SetCtrlAttribute (gPanel, PANEL_DISCONNECT, ATTR_DIMMED, 0);
SetCtrlAttribute (gPanel, PANEL_SEND, ATTR_DIMMED, 0);
SetCtrlAttribute (gPanel, PANEL_DATA, ATTR_DIMMED, 0);
Done:
return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -