?? echosrv.c
字號:
/*
* 服務器程序只能運行在 Windows NT,
* version 3.51 或更高的版本上.
* 不能運行在 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 追蹤 每一個單獨的文件句柄
// 的I/O 端口的狀態.
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];
};
/*結構體定義*/
//試卷每道題的結構
struct TestRubric{
char Questions[512];
char SelectObject[4][256];
};
//時間結構
//生成的試卷
//
// 全局變量
//
HANDLE ghCompletionPort;
//數據庫全局變量
SQLHANDLE hEnv; //ODBC環境句柄
SQLHANDLE hConn; //ODBC連接句柄
SCHAR * strConnect ="DRIVER={Microsoft Access Driver (*.mdb)};DBQ=";
SCHAR * DBName="exam.mdb";
SCHAR ProgPath[256];
char Conn[256]; //ODBC驅動連接返完整字符返回緩沖區
SCHAR ConnectString[1024];
char UserAttrib[50];
//
// 函數申明
//
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);
//數據庫操作函數
void ODBCConnect(SCHAR *strConnect,SCHAR *ProgPath,SCHAR *DBName); //ODBC數據連接子程序
BOOL LoginSever(char * LpText,struct User *login,char *p); //登陸操作函數
BOOL GetState(struct User US,char *p); //獲取試卷狀態子函數
int GetNumbers(struct User US,char *P); //獲取試卷狀態子函數
BOOL initTestPapers(struct User US,int Num,struct TestRubric * TestPapers); //初始化試卷
void GetQuestions(struct TestRubric * TestPapers,char * buffers); //發送緩沖區格式化試題子函數;
BOOL ScanTime(struct User US,char * P,struct ContextKey *pCntx); //設置試卷狀態子函數
void ChangeState(struct User US,char State[5]);
void SaveResult(struct User US,char Result[1024]);
BOOL GetResult(struct User US,char *p); //獲得試卷做答子函數
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("* 考試系統服務端程序 *\n");
printf("* 服務器程序只能運行在 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); //建立數據庫聯接
CheckOsVersion();
err = WSAStartup (0x0101, &WsaData);
if (err == SOCKET_ERROR)
{
FatalError("網絡初始化失敗.");
return EXIT_FAILURE;
}
listener = socket(AF_INET, SOCK_STREAM, 0); //開啟一個socket 套節字
if (listener < 0)
{
FatalError("socket() 錯誤-請檢查 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() 錯誤-請檢查 TCP/IP 是否正確安裝?");
ghCompletionPort = CreateIoCompletionPort(
INVALID_HANDLE_VALUE,
NULL,0,0);
if (ghCompletionPort == NULL)
FatalError("CreateIoCompletionPort() 錯誤-請檢查系統是否是Windows NT version 3.51 或更高版本.");
CreateWorkerThreads(ghCompletionPort);
listen(listener, 5);
fprintf(stderr, "服務器啟用 I/O Completion Ports 模式:端口 %d\n", SERV_TCP_PORT);
fprintf(stderr, "\nCtrl+C 停止服務器程序\n");
printf("\n-----------------------------------------------------------------------\n");
fprintf(stderr, "開始監聽客戶端:\n");
//
// 無限循環,接受并處理新的連接
//
for (;;)
{
struct ContextKey *pKey;
clientAddressLength = sizeof(clientAddress);
newsocket = accept(listener,
(struct sockaddr *)&clientAddress,
&clientAddressLength);
if (newsocket < 0)
{
FatalError("accept() 錯誤.");
return EXIT_FAILURE;
}
/*
*建立一個 key 并初始化它.
*/
pKey = calloc(1, sizeof(struct ContextKey)); // calloc 將使 buffer 區域清零.
pKey->sock = newsocket;
pKey->ovOut.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);//為寫信息包過程設置(事件對象) 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);
}
}
//
// 每一個工作線程從這里開始.
//
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);
// 無限循環從 I/O completion port 獲取信息.
for (;;)
{
bResult = GetQueuedCompletionStatus(
&dwNumRead,
&(DWORD)pCntx,
&lpOverlapped,
INFINITE
);
if (bResult == FALSE
&& lpOverlapped == NULL)
{
FatalError(
"ThreadFunc - GetQueuedCompletionStatus()錯誤.\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, "用戶已經關閉端口.\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試卷狀態設置成功.\n",users.Name,users.Subject);
else
{
fprintf(stderr,"設置 %s 的 %s 試卷狀態失敗.\n",users.Name,users.Subject);
SendString("服務器設置試卷狀態失敗.",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 試卷總題數 %d 成功.\n",users.Subject,QueNums);
TestPapers=(struct TestRubric *)malloc(sizeof(struct TestRubric)*QueNums);
if(TestPapers==NULL)
fprintf(stderr,"申請動態內存失敗.");
else if(!initTestPapers(users,QueNums,TestPapers))
{
fprintf(stderr,"初始化試卷失敗.\n");
free(TestPapers);
}
else fprintf(stderr,"初始化試卷成功.\n");
}
else fprintf(stderr,"用戶獲取 %s 試卷總題數失敗.\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,"成功發送 %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);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -