⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 echosrv.c

📁 vc开发的管理系统
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 * 服务器程序只能运行在 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(
               ghCompletionPort,
               &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 + -