socket网络编程入门聊天室_windows下可运行代码

2 篇文章 0 订阅
1 篇文章 0 订阅

socket网络编程入门聊天室_windows下代码

暂时先放下代码 存下 自己写得有很多得不足

  1. close clientlist应该在客户端断开连接 进行删除 不过自己还没咋搞明白后面
  2. 其次就是 select 只看一个描述符 而且第一个参数只是在限制(最大的描述符是多少)maxfd + 1 吗 网上都是这样说 书上说的又很简单 搜也没搜到 还要研究一下
    答 : select感知到描述符变化的必要条件是, 第一个参数要合理, 比如定义为fdmax+1, 且把需要检测的描述符set到描述集中。 window 下 设置成-1 就行 select 函数第一个参数并不是表示从0遍历到famax, 而我目前查到的仅仅是 最大值加一 书上也是就这样写了一行
  3. 我其实客户端 是想把 输入 和 获得服务端数据 都用作描述符 放进select的 可惜我找了好一会 没找到 win10 下 标准IO的描述符 也不知道这么搞 就起了一个线程
  4. 代码可以在win10 下跑 我用的MinGW 如果你要跑代码试验的话, 应该直接可以的 (有些人可能需要ws2_32.dll 可能 百度下一下)

unix 网络编程 自己实现的应该TCP 长连接的 聊天室。。。。。。。。 肯定有很多不足 和写的不好的地方见谅 这里只是我作为入门的一个开始练手
后续 看书 我会慢慢完善的 这里先放下代码
2020/7/8 22:56 更 留言 准备下班了 要努力学习啊
7/9答二 发现代码服务端贴错了

服务端代码

#include <bits/stdc++.h>
#include <winsock2.h>
#include <ws2tcpip.h>
// #pragma comment(lib, "ws2_32.lib")

#define PORT 9527
#define IP "127.0.0.1"

int g_ServerFd;
struct sockaddr_in g_Servaddr;
socklen_t g_ServaddrLen;
std::list<int> g_ClientList; //用list来存放套接字,没有限制套接字的容量就可以实现一个server跟若干个client通信

void getConn() {
    while (1) {
        int conn = accept(g_ServerFd, (struct sockaddr *)&g_Servaddr, &g_ServaddrLen);
        g_ClientList.push_back(conn);
        printf("创建新连入client的文件符 %d \n", conn);
    }
}

void sendMsg() {
	while(1) {
        char buf[1024];
        fgets(buf, sizeof(buf), stdin);
        for (auto it = g_ClientList.begin(); it != g_ClientList.end(); ++it) 
            send(*it, buf, sizeof(buf), 0);
    }
}

void getMsg() {
    struct timeval tv;
    tv.tv_sec = 0.1; //设置倒计时时间
    tv.tv_usec = 0;
    while (1) {
        for (auto it = g_ClientList.begin(); it != g_ClientList.end(); ++it) {
            fd_set rfds;
            FD_ZERO(&rfds);
            int maxfd = 0;
            int retval = 0;
            FD_SET(*it, &rfds);
            if (maxfd < *it) maxfd = *it;
			retval = select(maxfd + 1, &rfds, NULL, NULL, &tv);
	        if (retval == -1) {
	            printf("select error\n");
	        }
	        else if (retval == 0) {
	            //pass
	        }
	        else {
	            char buf[1024];
	            memset(buf, 0, sizeof(buf));
	            int len = recv(*it, buf, sizeof(buf), 0);
	            printf("%s", buf);
	            for(auto i : g_ClientList) {
	                if(i != *it) send(i, buf, sizeof(buf), 0);
	            }
	        }
        }
        Sleep(1);
    }
}

void init() {
    WORD sockVersion = MAKEWORD(2, 2);
    WSADATA wsaData;
    if (WSAStartup(sockVersion, &wsaData) != 0) //通过一个进程初始化ws2_32.dll
    {
        std::cout << "Initialize WSA failed" << std::endl;
        exit(1);
    } // window 得 这样 linux 下 库全 没这么麻烦

    g_ServerFd = socket(AF_INET, SOCK_STREAM, 0);
    memset(&g_Servaddr, 0, sizeof(g_Servaddr));
    g_Servaddr.sin_family = AF_INET;
    g_Servaddr.sin_port = htons(PORT);
    g_Servaddr.sin_addr.s_addr = inet_addr(IP);

    if (bind(g_ServerFd, (struct sockaddr *)&g_Servaddr, sizeof(g_Servaddr)) == -1) {
        perror("bind");
        exit(1);
    }
    if (listen(g_ServerFd, 200) == -1) {
        perror("listen");
        exit(1);
    }
    g_ServaddrLen = sizeof(g_Servaddr);
    std::thread t(getConn);
    t.detach(); //detach的话后面的线程不同等前面的进程完成后才能进行,如果这里改为join则前面的线程无法判断结束,就会等待 
    std::thread t1(sendMsg);
    t1.detach();
    std::thread t2(getMsg);
    t2.detach();
}

int main() {
    init();
    while(1);
    return 0;
}

客户端代码:

#include <bits/stdc++.h>
#include <winsock2.h>
#include <ws2tcpip.h>

#define MYPORT 9527
#define BUFFER_SIZE 1024

int g_ClientFD;
fd_set ReadFd;
struct sockaddr_in g_Servaddr;
int retval, maxfd;


void sendMsg() {
    while (1) {
        char buf[1024];
        fgets(buf, sizeof(buf), stdin);
        send(g_ClientFD, buf, sizeof(buf), 0);
    }
}

void init() {
    WORD sockVersion = MAKEWORD(2, 2);
    WSADATA wsaData;
    if (WSAStartup(sockVersion, &wsaData) != 0) //通过一个进程初始化ws2_32.dll
    {
        std::cout << "Initialize WSA failed" << std::endl;
        exit(0); 
    }

    g_ClientFD = socket(AF_INET, SOCK_STREAM, 0);
    memset(&g_Servaddr, 0, sizeof(g_Servaddr));
    g_Servaddr.sin_family = AF_INET;
    g_Servaddr.sin_port = htons(MYPORT);                 ///服务器端口
    g_Servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); ///服务器ip

    if (connect(g_ClientFD, (struct sockaddr *)&g_Servaddr, sizeof(g_Servaddr)) == -1)
    {
        perror("connect");
        exit(1);
    }
}

void run() {
    std::thread t(sendMsg); // 读取是单独的一个线程
    t.detach();
    struct timeval tv;
    tv.tv_sec = 0.1;
    tv.tv_usec = 0;
    while (1) {
        /*把可读文件描述符的集合清空*/
        FD_ZERO(&ReadFd);
		FD_SET(g_ClientFD, &ReadFd);
        maxfd = 0;
        /*把当前连接的文件描述符加入到集合中*/
        if(maxfd < g_ClientFD) maxfd = g_ClientFD;
        retval = select(maxfd + 1, &ReadFd, NULL, NULL, &tv);
        if (retval == -1) {
            printf("select出错,客户端程序退出\n");
            exit(0);
        } else if (retval == 0){
           //pass
        } else {
            /*服务器发来了消息*/
            if (FD_ISSET(g_ClientFD, &ReadFd)) {
                char recvbuf[BUFFER_SIZE];
                int len;
                len = recv(g_ClientFD, recvbuf, sizeof(recvbuf), 0);
                printf("%s", recvbuf);
                memset(recvbuf, 0, sizeof(recvbuf));
            }
        }
    }
}

int main()
{
    init();
    run();
	while(1);
    return 0;
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值