io模型 select

 

 

 

 

 

 

 


 

server.cpp

#include <winsock2.h>
#include <iostream>


using namespace std;

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


int main() {
    //初始化winsock的环境
    WSADATA wd;
    if (WSAStartup(MAKEWORD(2, 2), &wd) == SOCKET_ERROR) {
        cout << "WSAStartup error" << GetLastError() << endl;
        return 0;
    }

    //1 创建监听套接字
    SOCKET sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sListen == INVALID_SOCKET) {
        cout << "socket error" << GetLastError() << endl;
        return 0;
    }
    //2 绑定到ip 端口
    sockaddr_in addr;
    addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
    addr.sin_port = htons(8000);
    addr.sin_family = AF_INET;
    int len = sizeof(sockaddr_in);
    if (bind(sListen, (SOCKADDR*)&addr, len) == SOCKET_ERROR) {
        cout << "bind error:" << GetLastError() << endl;
        return 0;
    }

    //3监听套接字
    if (listen(sListen, 5) == SOCKET_ERROR) {
        cout << "listen error:" << GetLastError() << endl;
        return 0;
    }
    //4 select 开始
    //定义一个读 (接收消息)的集合
    fd_set readSet;
    //初始化集合
    FD_ZERO(&readSet);
    FD_SET(sListen, &readSet);

    //不停的 select 才可以读取套接字的状态改变
    while (true)
    {
        //临时的集合
        fd_set tmpSet;
        FD_ZERO(&tmpSet);
        //每次循环都是所有的套接字
        tmpSet = readSet;

        //利用select 选择出集合中可以读写的套接字
        int ret = select(0, &tmpSet, NULL, NULL, NULL);
        //最后一个参数 是null 一直等待
        if (ret == SOCKET_ERROR) {
            continue;
        }

        //成功筛选出来tmpSet可以发送 或者 接收 的socket
        for (int i = 0; i < tmpSet.fd_count; ++i) {
            //获取到套接字
            SOCKET s = tmpSet.fd_array[i];
            //接收到客户端的链接
            if (s == sListen) {

                SOCKET c = accept(s, NULL, NULL);
                //fd_set集合最大值64
                if (readSet.fd_count < FD_SETSIZE) {

                    //往集合中添加客户端套接字
                    FD_SET(c, &readSet);
                    cout << "欢迎" << c << "进入聊天室!" << endl;

                    //给客户端发送
                    char buf[100] = { 0 };
                    sprintf(buf, "欢迎%d进入聊天室!", c);

                    send(c, buf, 100, 0);

                }
                else {
                    cout << "达到客户端容量上线" << endl;

                }

            }
            else {

                //接收客户端的数据
                char buf[100] = { 0 };
                ret = recv(s, buf, 100, 0);
                if (ret == SOCKET_ERROR || ret == 0) {
                    closesocket(s);
                    FD_CLR(s, &readSet);
                    cout << s << "离开聊天室" << endl;
                }
                else {
                    cout << s << "说:" << buf << endl;
                }

            }

        }


    }
    //关闭监听套接字
    closesocket(sListen);

    WSACleanup();

    return 0;

}

 

 

 

client.cpp

#include <winsock2.h>
#include <iostream>

using namespace std;
//指定动态库的lib文件
#pragma comment(lib,"ws2_32.lib")



int main() {


    WSADATA wd;

    if (WSAStartup(MAKEWORD(2, 2), &wd) != 0) {
        cout << "WSAStartup error:" << GetLastError() << endl;
        return 0;
    }



    //1 创建流式套接字
    SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (s == INVALID_SOCKET) {
        cout << "socket error:" << GetLastError() << endl;
        return 0;
    }
    //2 绑定端口,ip
    sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(8000);
    addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");

    int len = sizeof(sockaddr_in);

    if (connect(s, (sockaddr*)&addr, len) == SOCKET_ERROR) {
        cout << "connect error:" << GetLastError() << endl;
        return 0;
    }

    //3接收服务端的消息
    char buf[100] = { 0 };
    recv(s, buf, 100, 0);
    cout << buf << endl;

    //3随时给服务端发消息
    int ret = 0;
    do {

        char buf[100] = { 0 };
        cout << "请输入聊天内容:";
        cin >> buf;

        ret = send(s, buf, 100, 0);


    } while (ret != SOCKET_ERROR && ret != 0);



    //4关闭监听套接字
    closesocket(s);
    WSACleanup();

    return 0;

}

 

posted @ 2024-07-24 21:36  AngDH  阅读(2)  评论(0编辑  收藏  举报