win32線程之完成連接埠

來源:互聯網
上載者:User
 

完成連接埠之伺服器篇

/* * EchoSrv.c * * Sample code for Multithreading Applications in Win32 * This is from Chapter 6, Listing 6-4 * * Demonstrates how to use I/O completion ports * with TCP on the Internet.  This sample * server can only be run on Windows NT, * version 3.51 or later.  The client (EchoCli) * can be run on 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 "MtVerify.h"// Pick a port number that seems to be away from all others#define SERV_TCP_PORT 5554#define MAXLINE 512//// Structure definition//// The context key keeps track of how the I/O// is progressing for each individual file handle.struct ContextKey{    SOCKET  sock;    // Input    char        InBuffer[4];    OVERLAPPED  ovIn;    // Output    int         nOutBufIndex;//總位元組intnCurrentBufIndex;//每次讀取的個數    char        OutBuffer[MAXLINE];    OVERLAPPED  ovOut;    DWORD       dwWritten;};//// Global variables//HANDLE ghCompletionPort;//// Function prototypes//void CreateWorkerThreads();DWORD WINAPI ThreadFunc(LPVOID pvoid);void IssueRead(struct ContextKey *pCntx);void CheckOsVersion();void FatalError(char *s);///////////////////////////////////////////////////////int main(int argc, char *argv[]){    SOCKET  listener;    SOCKET  newsocket;    WSADATA WsaData;    struct sockaddr_in serverAddress;    struct sockaddr_in clientAddress;    int     clientAddressLength;    int     err;    CheckOsVersion();    err = WSAStartup (0x0101, &WsaData);    if (err == SOCKET_ERROR)    {        FatalError("WSAStartup Failed");        return EXIT_FAILURE;    }    /*     * Open a TCP socket connection to the server     * By default, a socket is always opened     * for overlapped I/O.  Do NOT attach this     * socket (listener) to the I/O completion     * port!     */    listener = socket(AF_INET, SOCK_STREAM, 0);    if (listener < 0)    {        FatalError("socket() failed");        return EXIT_FAILURE;    }    /*     * Bind our local address     */    memset(&serverAddress, 0, sizeof(serverAddress));    serverAddress.sin_family      = AF_INET;    serverAddress.sin_addr.s_addr = htonl(INADDR_ANY);//inet_addr    serverAddress.sin_port        = htons(SERV_TCP_PORT);    err = bind(listener,            (struct sockaddr *)&serverAddress,            sizeof(serverAddress)          );    if (err < 0)        FatalError("bind() failed");    ghCompletionPort = CreateIoCompletionPort(            INVALID_HANDLE_VALUE,            NULL,   // No prior port            0,      // No key            0       // Use default  # of threads            );    if (ghCompletionPort == NULL)        FatalError("CreateIoCompletionPort() failed");    CreateWorkerThreads(ghCompletionPort);    listen(listener, 5);    fprintf(stderr, "Echo Server with I/O Completion Ports\n");    fprintf(stderr, "Running on TCP port %d\n", SERV_TCP_PORT);    fprintf(stderr, "\nPress Ctrl+C to stop the server\n");    //    // Loop forever accepting requests new connections    // and starting reading from them.    //    for (;;)    {        struct ContextKey *pKey;        clientAddressLength = sizeof(clientAddress);        newsocket = accept(listener,                            (struct sockaddr *)&clientAddress,                            &clientAddressLength);        if (newsocket < 0)        {            FatalError("accept() Failed");            return EXIT_FAILURE;        }        // Create a context key and initialize it.        // calloc will zero the buffer        pKey = calloc(1, sizeof(struct ContextKey));        pKey->sock = newsocket;        pKey->ovOut.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);        // Set the event for writing so that packets        // will not be sent to the completion port when        // a write finishes.        pKey->ovOut.hEvent = (HANDLE)((DWORD)pKey->ovOut.hEvent | 0x1);        // Associate the socket with the completion port        CreateIoCompletionPort(                (HANDLE)newsocket,                ghCompletionPort,                (DWORD)pKey,   // No key                0              // Use default # of threads            );        // Kick off the first read        IssueRead(pKey);    }    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);    }}//// Each worker thread starts here.DWORD WINAPI ThreadFunc(LPVOID pVoid){    BOOL    bResult;    DWORD   dwNumRead;    struct ContextKey *pCntx;    LPOVERLAPPED lpOverlapped;    UNREFERENCED_PARAMETER(pVoid);    // Loop forever on getting packets from    // the I/O completion port.    for (;;)    {        bResult = GetQueuedCompletionStatus(               ghCompletionPort,               &dwNumRead,               &(DWORD)pCntx,               &lpOverlapped,               INFINITE            );        if (bResult == FALSE            && lpOverlapped == NULL)        {            FatalError(                "ThreadFunc - Illegal call to GetQueuedCompletionStatus");        }        else if (bResult == FALSE            && lpOverlapped != NULL)        {            // This happens occasionally instead of            // end-of-file. Not sure why.            closesocket(pCntx->sock);            free(pCntx);            fprintf(stderr,                "ThreadFunc - I/O operation failed\n");        }        else if (dwNumRead == 0)        {            closesocket(pCntx->sock);            free(pCntx);            fprintf(stderr, "ThreadFunc - End of file.\n");        }        // Got a valid data block!        // Save the data to our buffer and write it        // all back out (echo it) if we have see a \n        else        {            // Figure out where in the buffer to save the character//            char *pch = &pCntx->OutBuffer[pCntx->nOutBufIndex++];memcpy(pCntx->OutBuffer + pCntx->nOutBufIndex ,pCntx->InBuffer,pCntx->nCurrentBufIndex);pCntx->nOutBufIndex += pCntx->nCurrentBufIndex;// //             *pch++ = pCntx->InBuffer[0];//             *pch = '\0';    // For debugging, WriteFile doesn't care            if (pCntx->InBuffer[pCntx->nCurrentBufIndex - 1] == '\n')            {pCntx->OutBuffer[pCntx->nOutBufIndex] = '\0';                WriteFile(                        (HANDLE)(pCntx->sock),                        pCntx->OutBuffer,                        pCntx->nOutBufIndex,                        &pCntx->dwWritten,                        &pCntx->ovOut                    );                pCntx->nOutBufIndex = 0;                fprintf(stderr, "Echo on socket %x.\n", pCntx->sock);            }            // Start a new read            IssueRead(pCntx);        }    }    return 0;}/* * Call ReadFile to start an overlapped request * on a socket.  Make sure we handle errors * that are recoverable. */void IssueRead(struct ContextKey *pCntx){    int     i = 0;    BOOL    bResult;    int     err;    int     numRead;    while (++i)    {        // Request a single character        bResult = ReadFile(                    (HANDLE)pCntx->sock,                    pCntx->InBuffer,                    1,//每次接受的個數                    &numRead,                    &pCntx->ovIn                );        // It succeeded immediately, but do not process it        // here, wait for the completion packet.        if (bResult){pCntx->nCurrentBufIndex = numRead;            return;}        err = GetLastError();        // This is what we want to happen, it's not an error        if (err == ERROR_IO_PENDING)            return;        // Handle recoverable error        if ( err == ERROR_INVALID_USER_BUFFER ||             err == ERROR_NOT_ENOUGH_QUOTA ||             err == ERROR_NOT_ENOUGH_MEMORY )        {            if (i == 5) // I just picked a number            {                Sleep(50);  // Wait around and try later                continue;            }            FatalError("IssueRead - System ran out of non-paged space");        }        break;    }    fprintf(stderr, "IssueRead - ReadFile failed.\n");}//// Make sure we are running under the right versions// of Windows NT (3.51, 4.0, or later)//void CheckOsVersion(){    OSVERSIONINFO   ver;    BOOL            bResult;    ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);    bResult = GetVersionEx((LPOSVERSIONINFO) &ver);    if ( (!bResult) ||         (ver.dwPlatformId != VER_PLATFORM_WIN32_NT) )    {        FatalError("ECHOSRV requires Windows NT 3.51 or later.");    }}//// Error handler//void FatalError(char *s){    fprintf(stdout, "%s\n", s);    exit(EXIT_FAILURE);}
完成連接埠之用戶端
/* * EchoCli.c * * Sample code for "Multithreading Applications in Win32" * This is from Chapter 6. * * This is a command line client to drive the ECHO server. * Run the server in one Commmand Prompt Window, * then run this program in one or more other windows. * EchoCli will wait for you to type in some text when * it starts up. Each line of text will be sent to the * echo server on TCP port 5554. */#include <windows.h>#include <tchar.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <winsock.h>/* Function Prototypes */void FatalError(char *s);int writen(SOCKET sock, char *ptr, int nBytes);int readline(SOCKET sock, char *ptr, int maxlen);void DoClientLoop(FILE *fp, SOCKET sock);/* Constants */#define MAXLINE 512#define SERVER_TCP_PORT5554#define SERVER_ADDRESS"127.0.0.1"/* * Error handler */void FatalError(char *s){    fprintf(stdout, "%s\n", s);    exit(EXIT_FAILURE);}/* * Write bytes to the port with proper block size handling. */int writen(SOCKET sock, char *ptr, int nBytes){    int nleft;    int nwritten;    nleft = nBytes;    while (nleft > 0)    {       nwritten = send(sock,                   ptr,                   nBytes,                   0          );       if (nwritten == SOCKET_ERROR)       {          fprintf(stdout, "Send Failed\n");          exit(1);       }        nleft -= nwritten;        ptr += nwritten;    }    return nBytes - nleft;}/* * Read a line of text of the port. This version * is very inefficient, but it's simple. */int readline(SOCKET sock, char *ptr, int maxlen){    int n;    int rc;    char c;    for (n=1; n<maxlen; n++)    {        if ( ( rc= recv(sock, &c, 1, 0)) == 1)        {            *ptr++ = c;            if (c=='\n')                break;        }        else if (rc == 0)        {            if (n == 1)                return 0;            else                break;        }        else            return -1;  /* Error */    }    *ptr = '\0';    return n;}int main(int argc, char *argv[]){    WSADATA WsaData;    SOCKET sock;    struct sockaddr_in  serv_addr;    int err;    puts("EchoCli - client for echo server sample program\n");    puts("Type a line of text followed by Return.");    puts("Exit this program by typing Ctrl+Z followed by Return.");    err = WSAStartup(0x0101, &WsaData);    if (err == SOCKET_ERROR)        FatalError("WSAStartup Failed");    /*     * Bind our local address     */    memset(&serv_addr, 0, sizeof(serv_addr));    serv_addr.sin_family    = AF_INET;    // Use the local host    serv_addr.sin_addr.s_addr   = inet_addr(SERVER_ADDRESS);    serv_addr.sin_port          = htons(SERVER_TCP_PORT);    /*     * Open a TCP socket (an Internet stream socket)     */    sock = socket(AF_INET, SOCK_STREAM, 0);    if (sock < 0)        FatalError("socket() failed -- do you have TCP/IP networking installed?");    if (connect(sock, (struct sockaddr *) &serv_addr,                sizeof(serv_addr)) < 0)        FatalError("connect() failed -- is the server running?");    DoClientLoop(stdin, sock);    closesocket(sock);    return EXIT_SUCCESS;}/* * As long as there is input from "fp", copy it to * the server, read what the server gives back, * and print it. */void DoClientLoop(FILE *fp, SOCKET sock){    int n;    char sendline[MAXLINE];    char recvline[MAXLINE+1];    while (fgets(sendline, MAXLINE, fp) != NULL)    {        n = strlen(sendline);        if (writen(sock, sendline, n) != n)            FatalError("DoClientLoop: writen() error");        n = readline(sock, recvline, MAXLINE);        if (n < 0)            FatalError("DoClientLoop: readline() error");        recvline[n] = '\0';        fputs(recvline, stdout);    }    if (ferror(fp))        FatalError("DoClientLoop: error reading file");}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.