?? echosrv.c
字號:
/*
* 服務(wù)器程序只能運(yùn)行在 Windows NT,
* version 3.51 或更高的版本上.
* 不能運(yùn)行在 Windows 95 上.
*/
#define WIN32_LEAN_AND_MEAN
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <tchar.h>
#include <string.h>
#include <winsock.h>
#include <io.h>
#include <ODBCINST.H>
#include <SQLEXT.H>
#include <time.h>
#include <winbase.h>
#include "MtVerify.h"
#pragma comment (lib,"WS2_32.lib")
#pragma comment (lib,"ODBC32.lib")
#define SERV_TCP_PORT 5554
#define MAXLINE 1024
// 用 key 追蹤 每一個(gè)單獨(dú)的文件句柄
// 的I/O 端口的狀態(tài).
struct ContextKey
{
SOCKET sock;
char InBuffer[4]; // 輸入
OVERLAPPED ovIn;
int nOutBufIndex;
char OutBuffer[MAXLINE]; // 輸出
OVERLAPPED ovOut;
DWORD dwWritten;
};
struct User
{
char Subject[50];
char Name[50];
char PassWord[50];
};
/*結(jié)構(gòu)體定義*/
//試卷每道題的結(jié)構(gòu)
struct TestRubric{
char Questions[512];
char SelectObject[4][256];
};
//時(shí)間結(jié)構(gòu)
//生成的試卷
//
// 全局變量
//
HANDLE ghCompletionPort;
//數(shù)據(jù)庫全局變量
SQLHANDLE hEnv; //ODBC環(huán)境句柄
SQLHANDLE hConn; //ODBC連接句柄
SCHAR * strConnect ="DRIVER={Microsoft Access Driver (*.mdb)};DBQ=";
SCHAR * DBName="exam.mdb";
SCHAR ProgPath[256];
char Conn[256]; //ODBC驅(qū)動(dòng)連接返完整字符返回緩沖區(qū)
SCHAR ConnectString[1024];
char UserAttrib[50];
//
// 函數(shù)申明
//
void CreateWorkerThreads();
DWORD WINAPI ThreadFunc(LPVOID pvoid);
void IssueRead(struct ContextKey *pCntx);
void CheckOsVersion();
void FatalError(char *s);
void SendString(char *p,struct ContextKey *pCntx);
//數(shù)據(jù)庫操作函數(shù)
void ODBCConnect(SCHAR *strConnect,SCHAR *ProgPath,SCHAR *DBName); //ODBC數(shù)據(jù)連接子程序
BOOL LoginSever(char * LpText,struct User *login,char *p); //登陸操作函數(shù)
BOOL GetState(struct User US,char *p); //獲取試卷狀態(tài)子函數(shù)
int GetNumbers(struct User US,char *P); //獲取試卷狀態(tài)子函數(shù)
BOOL initTestPapers(struct User US,int Num,struct TestRubric * TestPapers); //初始化試卷
void GetQuestions(struct TestRubric * TestPapers,char * buffers); //發(fā)送緩沖區(qū)格式化試題子函數(shù);
BOOL ScanTime(struct User US,char * P,struct ContextKey *pCntx); //設(shè)置試卷狀態(tài)子函數(shù)
void ChangeState(struct User US,char State[5]);
void SaveResult(struct User US,char Result[1024]);
BOOL GetResult(struct User US,char *p); //獲得試卷做答子函數(shù)
void ChangeState2(struct User US,char State[5],char Result[1024]);
///////////////////////////////////////////////////////
int main(int argc, char *argv[])
{
SOCKET listener;
SOCKET newsocket;
WSADATA WsaData;
struct sockaddr_in serverAddress;
struct sockaddr_in clientAddress;
int clientAddressLength;
int err;
printf("-----------------------------------------------------------------------\n");
printf("* 考試系統(tǒng)服務(wù)端程序 *\n");
printf("* 服務(wù)器程序只能運(yùn)行在 Windows NT,version 3.51 或更高的版本上. *\n");
printf("* -------- 2003.12.25 *\n");
printf("* yaomingmail@sina.com *\n");
printf("-----------------------------------------------------------------------\n");
GetCurrentDirectory(256,ProgPath); //獲得程序路徑
ProgPath[strlen(ProgPath)]='\\';
ODBCConnect(strConnect,ProgPath,DBName); //建立數(shù)據(jù)庫聯(lián)接
CheckOsVersion();
err = WSAStartup (0x0101, &WsaData);
if (err == SOCKET_ERROR)
{
FatalError("網(wǎng)絡(luò)初始化失敗.");
return EXIT_FAILURE;
}
listener = socket(AF_INET, SOCK_STREAM, 0); //開啟一個(gè)socket 套節(jié)字
if (listener < 0)
{
FatalError("socket() 錯(cuò)誤-請檢查 TCP/IP 是否正確安裝?");
return EXIT_FAILURE;
}
memset(&serverAddress, 0, sizeof(serverAddress));
serverAddress.sin_family = AF_INET;
serverAddress.sin_addr.s_addr = htonl(INADDR_ANY);
serverAddress.sin_port = htons(SERV_TCP_PORT);
err = bind(listener, // 綁定我們的局域地址
(struct sockaddr *)&serverAddress,
sizeof(serverAddress));
if (err < 0)
FatalError("bind() 錯(cuò)誤-請檢查 TCP/IP 是否正確安裝?");
ghCompletionPort = CreateIoCompletionPort(
INVALID_HANDLE_VALUE,
NULL,0,0);
if (ghCompletionPort == NULL)
FatalError("CreateIoCompletionPort() 錯(cuò)誤-請檢查系統(tǒng)是否是Windows NT version 3.51 或更高版本.");
CreateWorkerThreads(ghCompletionPort);
listen(listener, 5);
fprintf(stderr, "服務(wù)器啟用 I/O Completion Ports 模式:端口 %d\n", SERV_TCP_PORT);
fprintf(stderr, "\nCtrl+C 停止服務(wù)器程序\n");
printf("\n-----------------------------------------------------------------------\n");
fprintf(stderr, "開始監(jiān)聽客戶端:\n");
//
// 無限循環(huán),接受并處理新的連接
//
for (;;)
{
struct ContextKey *pKey;
clientAddressLength = sizeof(clientAddress);
newsocket = accept(listener,
(struct sockaddr *)&clientAddress,
&clientAddressLength);
if (newsocket < 0)
{
FatalError("accept() 錯(cuò)誤.");
return EXIT_FAILURE;
}
/*
*建立一個(gè) key 并初始化它.
*/
pKey = calloc(1, sizeof(struct ContextKey)); // calloc 將使 buffer 區(qū)域清零.
pKey->sock = newsocket;
pKey->ovOut.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);//為寫信息包過程設(shè)置(事件對象) event .
pKey->ovOut.hEvent = (HANDLE)((DWORD)pKey->ovOut.hEvent | 0x1);
CreateIoCompletionPort( //為請求綁定端口
(HANDLE)newsocket,
ghCompletionPort,
(DWORD)pKey,
0
);
IssueRead(pKey); // 完成第一次讀操作
}
SQLDisconnect(hConn);
SQLFreeHandle(SQL_HANDLE_DBC,hConn);
SQLFreeHandle(SQL_HANDLE_ENV, hEnv);
return 0;
}
void CreateWorkerThreads()
{
SYSTEM_INFO sysinfo;
DWORD dwThreadId;
DWORD dwThreads;
DWORD i;
GetSystemInfo(&sysinfo);
dwThreads = sysinfo.dwNumberOfProcessors * 2 + 2;
for (i=0; i<dwThreads; i++)
{
HANDLE hThread;
hThread = CreateThread(
NULL, 0, ThreadFunc, NULL, 0, &dwThreadId
);
CloseHandle(hThread);
}
}
//
// 每一個(gè)工作線程從這里開始.
//
DWORD WINAPI ThreadFunc(LPVOID pVoid)
{
struct User users;
struct TestRubric * TestPapers;
BOOL bResult;
DWORD dwNumRead;
struct ContextKey *pCntx;
LPOVERLAPPED lpOverlapped;
char Temp[50];
int i,QueNums;
char buffers[1024];
UNREFERENCED_PARAMETER(pVoid);
// 無限循環(huán)從 I/O completion port 獲取信息.
for (;;)
{
bResult = GetQueuedCompletionStatus(
ghCompletionPort,
&dwNumRead,
&(DWORD)pCntx,
&lpOverlapped,
INFINITE
);
if (bResult == FALSE
&& lpOverlapped == NULL)
{
FatalError(
"ThreadFunc - GetQueuedCompletionStatus()錯(cuò)誤.\n");
}
else if (bResult == FALSE
&& lpOverlapped != NULL)
{
// This happens occasionally instead of
// end-of-file. Not sure why.
closesocket(pCntx->sock);
free(pCntx);
fprintf(stderr,"用戶非正常退出.\n");
}
else if (dwNumRead == 0)
{
closesocket(pCntx->sock);
free(pCntx);
fprintf(stderr, "用戶已經(jīng)關(guān)閉端口.\n");
fprintf(stderr, "------------------.\n");
}
else
{
char *pch = &pCntx->OutBuffer[pCntx->nOutBufIndex++];
*pch++ = pCntx->InBuffer[0];
*pch = '\0';
if (pCntx->InBuffer[0] == '\n')
{
for(i=0;i<6;i++)
Temp[i]=pCntx->OutBuffer[i];
Temp[i]='\0';
if(!strcmp(Temp,"login:"))
{
if(LoginSever(pCntx->OutBuffer,&users,Temp))
SendString(Temp,pCntx);
else
SendString("無法識別的用戶.",pCntx);
}
else if(!strcmp(Temp,"Srecv:"))
{
for(i=0;i<7;i++)
Temp[i]=pCntx->OutBuffer[i+6];
Temp[i]='\0';
if (!strcmp(Temp,"ScanTm:"))
if(ScanTime(users,buffers,pCntx))
fprintf(stderr,"%s %s試卷狀態(tài)設(shè)置成功.\n",users.Name,users.Subject);
else
{
fprintf(stderr,"設(shè)置 %s 的 %s 試卷狀態(tài)失敗.\n",users.Name,users.Subject);
SendString("服務(wù)器設(shè)置試卷狀態(tài)失敗.",pCntx);
}
else if(!strcmp(Temp,"GetSta:"))
{
if(GetState(users,Temp))
SendString(Temp,pCntx);
}
else if(!strcmp(Temp,"GetRlt:"))
{
if (GetResult(users,buffers))
SendString(buffers,pCntx);
else SendString("Erro",pCntx);
}
else if(!strcmp(Temp,"GetNum:"))
{
if(QueNums=GetNumbers(users,buffers))
{
SendString(buffers,pCntx);
fprintf(stderr,"用戶獲取 %s 試卷總題數(shù) %d 成功.\n",users.Subject,QueNums);
TestPapers=(struct TestRubric *)malloc(sizeof(struct TestRubric)*QueNums);
if(TestPapers==NULL)
fprintf(stderr,"申請動(dòng)態(tài)內(nèi)存失敗.");
else if(!initTestPapers(users,QueNums,TestPapers))
{
fprintf(stderr,"初始化試卷失敗.\n");
free(TestPapers);
}
else fprintf(stderr,"初始化試卷成功.\n");
}
else fprintf(stderr,"用戶獲取 %s 試卷總題數(shù)失敗.\n",users.Subject);
}
else if(!strcmp(Temp,"GetQue:"))
{
for(i=0;pCntx->OutBuffer[i]!='\n';i++);
pCntx->OutBuffer[i]='\0';
i=0;
i=atoi(&pCntx->OutBuffer[13]);
GetQuestions(TestPapers+i,buffers);
SendString(buffers,pCntx);
fprintf(stderr,"成功發(fā)送 %s : %s 試卷的第 %d 題.\n",users.Name,users.Subject,i+1);
}
else if(!strcmp(Temp,"SaveDt:"))
{
SaveResult(users,&(pCntx->OutBuffer[13]));
}
else if(!strcmp(Temp,"ChanST:"))
ChangeState2(users,"3",&(pCntx->OutBuffer[13]));
}
else if(!strcmp(Temp,"trecv:")){}
else if(!strcmp(Temp,"arecv:")){}
else if(!strcmp(Temp,"ssave:")){}
else if(!strcmp(Temp,"tsave:")){}
else if(!strcmp(Temp,"asave:")){}
pCntx->nOutBufIndex = 0;
fprintf(stderr, " Echo on socket %x.\n", pCntx->sock);
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -