IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> 对于tcp/ip建立小型聊天室的代码 -> 正文阅读

[网络协议]对于tcp/ip建立小型聊天室的代码

客户端

// 三次握手主要是创建连接
// 四次挥手主要是释放资源
// I/O 复用  epoll模式


#include <iostream>
#include <arpa/inet.h>
#include <unistd.h>
#include <strings.h>    // bzero()
#include <thread>
//#include <sys/select.h>
#include <sys/epoll.h>   // epoll()
#include <linux/fs.h>   // OPEN_MAX
using namespace std;

string name;

void show_connect(int fd) {
    // 获取本地地址和端口
    struct sockaddr_in local_addr;
    socklen_t local_addr_len = sizeof(local_addr);
    bzero(&local_addr,local_addr_len);   //  清空   防止后面误用
    getsockname(fd,(struct sockaddr*)&local_addr,&local_addr_len);
    cout << "local " << inet_ntoa(local_addr.sin_addr) << ":" << ntohs(local_addr.sin_port) << endl;

    // 获取远程地址和端口
    struct sockaddr_in remote_addr;
    socklen_t remote_addr_len = sizeof(remote_addr);
    bzero(&remote_addr,remote_addr_len);
    getpeername(fd,(struct sockaddr*)&remote_addr,&remote_addr_len);
    cout << "remote " << inet_ntoa(remote_addr.sin_addr) << ":" << ntohs(remote_addr.sin_port) << endl;

}

//  ./clinet IP port name
int main(int argc,char* argv[]) {
    if(4!=argc) {
        cout << "Usage:" << argv[0] << " IP port name" << endl;
        return 1;
    }
    name = argv[3];
    // 1.创建连接套接字
    int connfd = socket(AF_INET,SOCK_STREAM,0);
    if(-1 == connfd) {
        cout << "socket error" << endl;
        return 1;
    }

    // 2. 连接服务器
    struct sockaddr_in remote_addr;  // in是internet简写
    remote_addr.sin_family = AF_INET; // 协议  sin是sockaddr_in的缩写
    remote_addr.sin_addr.s_addr = inet_addr(argv[1]); // IP地址
    remote_addr.sin_port = htons(atoi(argv[2])); // 端口号   小端转大端
    if(-1==connect(connfd,(struct sockaddr*)&remote_addr,sizeof(remote_addr))) {
        cout << "connect error" << endl;
        return 1;
    } else {
        cout << "connect success" << endl;
        cout << inet_ntoa(remote_addr.sin_addr) << ":" << ntohs(remote_addr.sin_port) << endl;
        show_connect(connfd);
    }
    
    // 创建epoll描述符
    int epollfd = epoll_create(2);
    
    // 注册事件
    struct epoll_event evt;
    evt.data.fd = STDIN_FILENO;
    evt.events = EPOLLIN;
    epoll_ctl(epollfd,EPOLL_CTL_ADD,STDIN_FILENO,&evt);
    evt.data.fd = connfd;
    evt.events = EPOLLIN;
    epoll_ctl(epollfd,EPOLL_CTL_ADD,connfd,&evt);

bool stop = false;
    while(!stop) {
        int count = 2;
        struct epoll_event revt[2];
        int revt_count = epoll_wait(epollfd,revt,count,-1);
        for(int i=0;i<revt_count;++i){
            if(revt[i].data.fd == STDIN_FILENO && revt[i].events & EPOLLIN){
                // 3.发送信息
                string message;
                getline(cin,message);
                message = name + ":" + message;
                write(connfd,message.c_str(),message.size()+1);
            }else if(revt[i].data.fd == connfd && revt[i].events & EPOLLIN){
                // 4.接收数据
                char buffer[1024] = {0};
                int len = read(connfd,buffer,sizeof(buffer));
                if(len == 0) {
                    cout << "server exit" << endl;
                    epoll_ctl(epollfd,EPOLL_CTL_DEL,connfd,revt+i);
                    --count;
                    stop  = true;
                    break;
                } else {
                    cout << buffer<< endl;
                }
            }
        }
        
    }
    close(epollfd);
    // 5. 关闭套接字
    close(connfd);

    return 0;
}


服务端

// 一服务器 ->  多客户端
// 三次握手主要是创建连接
// 四次挥手主要是释放资源
// I/O复用 epoll模式


#include <iostream>
#include <arpa/inet.h>
#include <unistd.h>
#include <strings.h>   // bzero() 
#include <pthread.h>
#include <list>  // remove()
#include <thread>
#include <algorithm>  // max_element()
#include <sys/epoll.h>   // epoll()
#include <linux/fs.h>   // OPEN_MAX
using namespace std;

void show_connect(int fd) {
    // 获取本地地址和端口
    struct sockaddr_in local_addr;
    socklen_t local_addr_len = sizeof(local_addr);
    bzero(&local_addr,local_addr_len);  //  清空   防止后面误用
    getsockname(fd,(struct sockaddr*)&local_addr,&local_addr_len);
    cout << "local " << inet_ntoa(local_addr.sin_addr) << ":" << ntohs(local_addr.sin_port) << endl;

    // 获取远程地址和端口
    struct sockaddr_in remote_addr;
    socklen_t remote_addr_len = sizeof(remote_addr);
    bzero(&remote_addr,remote_addr_len);
    getpeername(fd,(struct sockaddr*)&remote_addr,&remote_addr_len);
    cout << "remote " << inet_ntoa(remote_addr.sin_addr) << ":" << ntohs(remote_addr.sin_port) << endl;

}

// ./server ip port
int main(int argc,char* argv[]) {
    if(3!=argc) {
        cout << "Usage:" << "输入 IP port" << endl;
        return 1;
    }

    // 1. 监听套接字
    int listenfd = socket(AF_INET,SOCK_STREAM,0);
    if(-1 == listenfd) {
        cout << "listen socket error" << endl;
        return 1;
    }

    // 为了避免端口被占用,想要再次使用同一个端口
    // 设置端口重复利用(一般用在调试中)
    int flag = 1;
    setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&flag,sizeof(flag));

    // 2. 绑定
    struct sockaddr_in local_addr;
    local_addr.sin_family = AF_INET; // IPv4协议
    local_addr.sin_addr.s_addr = inet_addr(argv[1]); // IP地址
    local_addr.sin_port = htons(atoi(argv[2])); // 端口号

    if(-1 == bind(listenfd,(struct sockaddr*)&local_addr,sizeof(local_addr))) { //套接字和端口绑定
        cout << "bind error" << endl;
        return 1;
    } else {
        cout << "bind success" << endl;
    }
    // 3. 监听设置
    if(-1==listen(listenfd,10)) {
        cout << "listen error" << endl;
        return 1;
    } else {
        cout << "listen success" << endl;
    }

    int epollfd = epoll_create(INR_OPEN_MAX);

    struct epoll_event evt;
    evt.data.fd = STDIN_FILENO;
    evt.events = EPOLLIN;
    epoll_ctl(epollfd,EPOLL_CTL_ADD,STDIN_FILENO,&evt); //监听标准输入
    evt.data.fd = listenfd;
    epoll_ctl(epollfd,EPOLL_CTL_ADD,listenfd,&evt); 

    int count = 2;
    list<int> fds;

    while(true) {
        struct epoll_event revt[count];
        int revt_cnt = epoll_wait(epollfd,revt,count,-1);
        for(int i=0; i<revt_cnt; ++i) {
            if(revt[i].data.fd == STDIN_FILENO && revt[i].events & EPOLLIN) { //如果事件是输入 并且文件描述符包括可读
                string message;
                getline(cin,message);
                cin.clear();  // 清空输入出错
                if(!message.empty()) { // 判断终端输入是否为空
                    message = "广告:" + message;
                    for(auto fd:fds) {
                        write(fd,message.c_str(),message.size()+1);
                    }
                }
            }else if(revt[i].data.fd == listenfd && revt[i].events & EPOLLIN) {
                struct sockaddr_in remote_addr;
                bzero(&remote_addr,sizeof(remote_addr));   // 清空
                socklen_t remote_addr_len = sizeof(remote_addr);
                int connfd = accept(listenfd,(struct sockaddr*)&remote_addr,&remote_addr_len);
                //int connfd = accept(listenfd,NULL,NULL);
                if(-1 == connfd) {
                    cout << "accept error" << endl;
                    return 1;
                } else {
                    cout << "accept success" << endl;
                    cout << inet_ntoa(remote_addr.sin_addr) << ":" << ntohs(remote_addr.sin_port) << endl;
                    show_connect(connfd);
                    //fds.push_back(connfd);
                    evt.data.fd = connfd;
                    evt.events = EPOLLIN;
                    epoll_ctl(epollfd,EPOLL_CTL_ADD,connfd,&evt);
                    fds.push_back(connfd);
                    ++count;
                }
            } else {
                int connfd = revt[i].data.fd;
                char buffer[1024] = {0};
                int n = read(connfd,buffer,1024);  // 读取客户端发过来的信息
                if(n == 0) {
                    cout << "client exit" << endl;
                    close(connfd);   // 关掉推出的连接
                    epoll_ctl(epollfd,EPOLL_CTL_DEL,connfd,revt+i);
                    fds.remove(connfd);
                    --count;
                    break;
                } else {
                    for(auto fd:fds) { // 发送信息给所有的客户端
                        if(fd == connfd) continue;
                        write(fd,buffer,1024);
                    }
                }
            }
        }
    }
    
    close(epollfd);
    // 7. 关闭套接字
    close(listenfd);
}

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2022-03-03 16:49:22  更:2022-03-03 16:51:47 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 8:55:24-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码