首页 > 代码库 > WinSockAPI多线程服务器

WinSockAPI多线程服务器

运行效果:

 

程序:

// TcpServer.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
#include <WinSock2.h>
#include <Windows.h>
#include <vector>
#include <algorithm>
using namespace std;
//包含库
#pragma comment(lib, "ws2_32.lib")
//发送最大字节数
#define MAXDATASIZE 100
#define BACKLOG 100
const int SERVERPORT = 9999;

//连接数
static int connum;

//客户端连接线程函数
DWORD WINAPI qtPingServerThreadFunc(LPVOID lpThreadParameter);
//客户连接socket数组
vector<SOCKET> client_fd;

int _tmain(int argc, _TCHAR* argv[])
{
    int err;

    SOCKET sockfd;

    struct sockaddr_in local_addr;
    struct sockaddr_in remote_addr;

    WORD wRequestVersion;
    WSADATA wsadata;
    wRequestVersion = MAKEWORD(2, 0);
    //启动socket服务
    err = WSAStartup(wRequestVersion, &wsadata);
    if (0 != err)
    {
        printf("Socket Error!\n");
        return 0;
    }

    if (LOBYTE(wsadata.wVersion) != 2 || HIBYTE(wsadata.wVersion) != 0)
    {
        WSACleanup();
        printf("Version Wrong!\n");
        return 0;
    }
    //创建socket
    sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    
    if (INVALID_SOCKET == sockfd)
    {
        printf("Socket Create Failed!\n");
        return 0;
    }
    else
    {
        printf("Socket Create Success!\n");
    }
    //定义服务器地址信息
    local_addr.sin_family = AF_INET;
    local_addr.sin_port = htons(SERVERPORT);
    //INADDR_ANY自动绑定地址
    local_addr.sin_addr.s_addr = INADDR_ANY;//inet_addr("172.16.254.212");
    memset(&(local_addr.sin_zero), 0, 8);
    //绑定socket到本机地址
    if (bind(sockfd, (struct sockaddr *)&local_addr, sizeof(struct sockaddr)) == -1)
    {
        printf("bind wrong!\n");
        return 0;
    }
    else
    {
        printf("bind success!\n");
    }

    int n = 0;
    unsigned long ul = 1;
    while (1)
    {
        //主线程监听
        if (listen(sockfd, BACKLOG) != -1)
        {
            printf("Listening...\n");

            int sin_size = sizeof(struct sockaddr_in);
            //取出连接的客户端socket
            SOCKET sock = accept(sockfd, (struct sockaddr *)&remote_addr, &sin_size);
            //设置socket为非阻塞
            ioctlsocket(sock,FIONBIO,(unsigned long *)&ul);//
            
            vector<SOCKET>::iterator itr_end = client_fd.end();
            vector<SOCKET>::iterator itr = find(client_fd.begin(), itr_end, sock);
            if (itr == itr_end)
            {
                client_fd.push_back(sock);
                printf("receive a connection from %s\n", inet_ntoa(remote_addr.sin_addr));
                connum++;
                
                printf("当前连接数:%d\n", connum);
            }
            
            DWORD dwPingThreadID;
            //创建新线程处理该客户socket连接
            HANDLE hPingHandle = CreateThread(0, 0, qtPingServerThreadFunc, (LPVOID)sock, 0, &dwPingThreadID);
        }
        Sleep(50);
    }

    for (int i = 0 ; i < client_fd.size(); i++)
    {
        closesocket(client_fd[i]);
    }
    client_fd.clear();
    WSACleanup();
    return 0;
}

DWORD WINAPI qtPingServerThreadFunc(LPVOID lpThreadParameter)
{
    SOCKET sock = (SOCKET)lpThreadParameter;

    int recvbytes;
    BYTE buf[MAXDATASIZE];

    while (1)
    {
        //接收数据
        recvbytes = recv(sock, (char *)buf, MAXDATASIZE, 0);
        //接收到的数据长度为0,则表示客户端主动断开连接
        if (recvbytes == 0)
        {
            printf("disconnect!\n");
            vector<SOCKET>::iterator itr_end = client_fd.end();
            vector<SOCKET>::iterator itr = find(client_fd.begin(), itr_end, sock);
            if (itr != itr_end)
            {
                client_fd.erase(itr);
            }
            connum--;
            printf("当前连接数:%d\n", connum);
            return 0;
        } 
        //接收信息,群发给所有客户端
        else if ((recvbytes) != -1)
        {
            buf[recvbytes] = \0;
            printf("Received: %s\n", buf);
            BYTE * head;
            head = buf;

            for (int i = 0; i < client_fd.size(); i++)
            {
                send(client_fd[i], (char *)buf, sizeof(buf), 0);    
            }
        }
        Sleep(50);
    }
    return 0;
}