美文网首页
聊天demo(select服务器端)

聊天demo(select服务器端)

作者: 量化程序猿 | 来源:发表于2019-12-30 15:23 被阅读0次

    1. windows 服务器端(select)

    #include <iostream>

    #include <winsock2.h>

    #include <windows.h>

    #pragma comment(lib,"Ws2_32.lib")

    #include <map>

    #include <thread>

    #include <vector>

    #include <mutex>

    #include <set>

    std::vector<SOCKET> fdVec;

    std::mutex gol_mutex;

    void LogPrint(const char* format, ...)

    {

    va_list args;

    va_start(args, format);

    char content[2048];

    memset(content, 0, sizeof(content));

    int ret = vsnprintf_s(content, 2048 - 1, format, args);

    if (ret < 0)

    {

    return;

    }

    printf(content);

    printf("\n");

    va_end(args);

    }

    class NetThread

    {

    public:

    NetThread()

    {

    FD_ZERO(&m_readSet);

    maxSocket = 0;

    }

    ~NetThread()

    {

    m_thread.join();

    }

    void SetThread(std::thread& t)

    {

    m_thread.swap(t);

    }

    void SetSockRead(SOCKET fd)

    {

    if (fd == -1)

    {

    return;

    }

    m_mutex.lock();

    FD_SET(fd, &m_readSet);

    if (fd > maxSocket)

    {

    maxSocket = fd;

    }

    m_mutex.unlock();

    }

    void run()

    {

    while (true)

    {

    timeval val;

    val.tv_sec = 0;

    val.tv_usec = 0;

    m_mutex.lock();

    fd_set tempReadSet = m_readSet;

    m_mutex.unlock();

    int ret = select(maxSocket + 1, &tempReadSet, NULL, NULL, &val);

    if (ret == -1)

    {

    continue;

    }

    for (auto& socket : fdVec)

    {

    if (FD_ISSET(socket, &tempReadSet))

    {

    ReadData(socket);

    }

    }

    //检测可删除列表,可用于心跳超时检测和发送失败检测

    if (delSet.size() != 0)

    {

    for (auto iter = fdVec.begin(); iter != fdVec.end(); )

    {

    if (delSet.find(*iter) != delSet.end())

    {

    m_mutex.lock();

    FD_CLR(*iter, &m_readSet);

    m_mutex.unlock();

    closesocket(*iter);

    iter = fdVec.erase(iter);

    continue;

    }

    ++iter;

    }

    delSet.clear();

    }

    }

    }

    private:

    void ReadData(SOCKET fd)

    {

    char buff[1024];

    memset(buff, 0, sizeof(buff));

    int ret = recv(fd, buff, sizeof(buff), 0);

    if (ret != -1)

    {

    //接收缓冲为空,表示已断开连接

    if (buff[0] == '\0')

    {

    LogPrint("fd(%d) 已断开连接...", fd);

    delSet.insert(fd);

    return;

    }

    LogPrint("fd = %d send MSG=%s", fd, buff);

    gol_mutex.lock();

    for (auto iter = fdVec.begin(); iter != fdVec.end(); ++iter)

    {

    ret = send(*iter, buff, sizeof(buff), 0);

    if (ret == -1)

    {

    LogPrint("fd(%d) 已断开连接...", *iter);

    delSet.insert(*iter);

    }

    }

    gol_mutex.unlock();

    }

    }

    private:

    //可读列表

    fd_set m_readSet;

    //线程句柄

    std::thread m_thread;

    //线程锁

    std::mutex m_mutex;

    //最大描述符

    SOCKET maxSocket;

    //可删除的socket列表

    std::set<SOCKET> delSet;

    };

    int main()

    {

    WORD wVersionRequested;

    WSADATA wsaData;

    wVersionRequested = MAKEWORD(2, 2);

    int err = WSAStartup(wVersionRequested, &wsaData);

    if (err != 0)

    {

    LogPrint("start up fail");

    return 1;

    }

    struct sockaddr_in addr;

    addr.sin_family = AF_INET;

    addr.sin_addr.s_addr = inet_addr("127.0.0.1");

    addr.sin_port = htons(10001);

    SOCKET main_fd = socket(PF_INET, SOCK_STREAM, 0);

    if (main_fd == -1)

    {

    LogPrint("create socket fail!");

    return 1;

    }

    if (bind(main_fd, (const sockaddr*)&addr, sizeof(sockaddr_in)) == -1)

    {

    LogPrint("bind fail!");

    return 1;

    }

    listen(main_fd, 2);

    NetThread netThread;

    std::thread t(&NetThread::run, &netThread);

    netThread.SetThread(t);

    LogPrint("服务器已启动!");

    while (true)

    {

    SOCKET new_sock = accept(main_fd, NULL, NULL);

    if (new_sock != -1)

    {

    char buff[1024] = "服务器已连接成功!";

    send(new_sock, buff, sizeof(buff), 0);

    LogPrint("fd = %d 已连接服务器...", new_sock);

    gol_mutex.lock();

    fdVec.push_back(new_sock);

    gol_mutex.unlock();

    netThread.SetSockRead(new_sock);

    }

    }

    WSACleanup();

    }

    2. 客户端

    #include <iostream>

    #include <winsock2.h>

    #include <windows.h>

    #pragma comment(lib,"Ws2_32.lib")

    #include <thread>

    void LogPrint(const char* format, ...)

    {

    va_list args;

    va_start(args, format);

    char content[2048];

    memset(content, 0, sizeof(content));

    int ret = vsnprintf_s(content, 2048 - 1, format, args);

    if (ret < 0)

    {

    return;

    }

    printf(content);

    printf("\n");

    va_end(args);

    }

    void ReadData(SOCKET fd)

    {

    while (true)

    {

    char buff[1024];

    memset(buff, 0, sizeof(buff));

    int ret = recv(fd, buff, sizeof(buff), 0);

    if (ret != -1)

    {

    LogPrint("fd=%d recv MSG=%s", fd, buff);

    }

    }

    }

    int main()

    {

    WORD wVersionRequested;

    WSADATA wsaData;

    wVersionRequested = MAKEWORD(2, 2);

    int err = WSAStartup(wVersionRequested, &wsaData);

    if (err != 0)

    {

    LogPrint("start up fail");

    return 1;

    }

    sockaddr_in addr;

    addr.sin_family = AF_INET;

    addr.sin_addr.s_addr = inet_addr("127.0.0.1");

    addr.sin_port = htons(10001);

    SOCKET main_fd = socket(PF_INET, SOCK_STREAM, 0);

    int ret = connect(main_fd, (const sockaddr*)&addr, sizeof(sockaddr_in));

    if (ret == -1)

    {

    LogPrint("connect fail!");

    return 1;

    }

    std::thread t(ReadData, main_fd);

    //t.detach();

    while (true)

    {

    char msg[1024];

    memset(msg, 0, sizeof(msg));

    scanf("%s", msg);

    send(main_fd, msg, sizeof(msg), 0);

    }

    WSACleanup();

    }

    相关文章

      网友评论

          本文标题:聊天demo(select服务器端)

          本文链接:https://www.haomeiwen.com/subject/ckhmoctx.html