当前位置: 首页> 教育> 培训 > 深圳外贸公司名单_站长百度_做百度推广的网络公司广州_付费内容网站

深圳外贸公司名单_站长百度_做百度推广的网络公司广州_付费内容网站

时间:2025/7/8 9:43:50来源:https://blog.csdn.net/weixin_56261190/article/details/145537988 浏览次数:0次
深圳外贸公司名单_站长百度_做百度推广的网络公司广州_付费内容网站

1.poll 模型

poll 函数原型 

函数原型:int poll(struct pollfd *fds, nfds_t nfds, int timeout);
功能描述:监视fds中的描述符是否激活
参数描述:参数 fds:是一个struct pollfd 结构体数组,该数组中存放了多个想要监视的描述符该结构体结构如下struct pollfd {int   fd;         /* 想要监视的描述符 */short events;     /* 确定fd描述,到底以何种形式进行监视 */POLLIN:监视fd描述是否可读POLLOUT:监视fd描述符是否可写                 short revents;    /* returned events */一般会随着结构体初始化为0,同步为0当 revents == 0的时候,表示fd这个描述符没有激活当 revents == POLLIN的时候,表示fd这个描述符可读激活了当 revents == POLLOUT的时候,表示fd这个描述可写激活了};参数 nfds:fds这个数组的长度参数 timeout:设置的最大监视时长注意:    单位是毫秒0表示不阻塞-1表示一直阻塞  实例struct pollfd arr[5] = {0}arr[0].fd = 0arr[0].events = POLLINpoll(arr) 表示监视 标准输入流是否可读

 poll模型 完整代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <poll.h>typedef struct sockaddr_un addr_un_t;void insert_fd(struct pollfd* arr, int* len, struct pollfd fd) {arr[*len] = fd;(*len)++;
}void remove_fd(struct pollfd* arr, int* len, int fd) {int i;for (i = 0; i < *len; i++) {if (fd == arr[i].fd) {break;}}for (int j = i; j < *len - 1; j++) {arr[j] = arr[j + 1];}(*len)--;
}int main(int argc, const char *argv[]) {if (argc != 2) {printf("请输入端口号\n");return 1;}// 准备一个用来存放所有连接上来的客户端描述符的数组int client_arr[64] = {};int client_arr_len = 0; // 这里修正了初始化为0int port = atoi(argv[1]); // 将字符串转换成int类型port// 创建服务器套接字int server = socket(AF_INET, SOCK_STREAM, 0);struct sockaddr_in addr = {0};addr.sin_port = htons(port);addr.sin_addr.s_addr = inet_addr("0.0.0.0");// 为套接字绑定ip和portif (bind(server, (struct sockaddr*)&addr, sizeof(addr)) == -1) {perror("bind");return 1;}// 监听listen(server, 10);struct pollfd arr[20] = {0};int len = 0;// 将stdin和server放到arr里面去struct pollfd poll_stdin = {.fd = 0, .events = POLLIN, .revents = 0};struct pollfd poll_server = {server, POLLIN, 0};insert_fd(arr, &len, poll_stdin);insert_fd(arr, &len, poll_server);while (1) {poll(arr, len, -1);for (int i = 0; i < len; i++) {if (arr[i].revents == 0) {continue; // 该描述符没激活,直接看下一个描述符}int fd = arr[i].fd;if (fd == server) {printf("有新客户端连接\n");// 这里应该接受客户端连接,并创建新的pollfd结构,然后调用insert_fd// 但由于代码不完整,这里省略了具体实现} else if (fd == 0) {char buf[64] = "";scanf("%63s", buf);printf("键盘输入数据:%s\n", buf);} else {// 剩下的都是客户端描述符了char buf[64];int res = read(fd, buf, 64);if (res == 0) {close(fd);} else {printf("%d#客户端发来消息:%s\n", fd, buf);}}}}return 0;
}

2.epoll模型 

epoll函数原型 

函数原型:int epoll_wait(int epfd, struct epoll_event *events,
int maxevents, int timeout);
功能描述:监视 epfd 里面的描述符是否被激活
参数描述:参数 epfd:epoll_wait的监视列表epfd其实是一个文件描述符,该描述符所描述的文件,才是epoll_wait的监视列表所以我们要做的就是,将所有想要被epoll监视的描述符,都放到 epfd 文件中去参数 events:用来存放所有激活了的描述符的数组,是一个结构体数组,结构如下struct epoll_event {uint32_t     events;    /* 在poll_wait函数里面,这个数据表示激活的描述符是以何种形式激活的 */epoll_data_t data;      /* 该数据里面存放了具体的激活的描述符是谁 */};typedef union epoll_data {void    *ptr;int      fd;    /* 具体的激活的描述符 */uint32_t u32;uint64_t u64;} epoll_data_t;其实epoll_wait 针对当前数组只做一件事将激活的描述符到底是谁,以及该描述符是如何激活的,存放到 events这个数组里面去参数 maxevents:想要监视的描述符的数量参数 timout:设定poll_wait最大阻塞时长0:表示不阻塞-1:表示永久阻塞单位为毫秒返回值:返回激活的描述符的数量实例struct epoll_event arr[5]epoll_wait(epfd,arr) 假设此时 epfd 里面有一个 0 和 一个 server此时 epoll_wait 监视到 server激活了arr就会发生改变,改变如下arr[0].events == EPOLLINarr[0].data.fd == server

 如何创建epfd

int epoll_create(int size);创建一个只能监视size个描述符的监视列表
int epoll_create1(int flags);flags一般传 EPOLL_CLOEXEC表示创建一个动态的监视列表,该监视列表的长度会随着想要监视的描述符数量的改变而改变
所以,一般来说,我们想要创建一个监视列表,直接写int epfd = epoll_create1(EPOLL_CLOEXEC);返回值:创建出来的监视列表的描述符

 如何向epfd中存入想要监视的描述符

函数原型:int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
功能描述:根据op(第2个参数)的不同,针对描述符做出不同的操作
参数描述:参数 epfd:监视列表自己的描述符参数 op:具体的操作EPOLL_CTL_ADD:将fd描述符,添加到epfd监视列表里面去EPOLL_CTL_DEL:将fd描述符,从epfd中移除EPOLL_CTL_MOD:更改fd描述的监视方式参数 event: 注意,这里是一个结构体地址,用来明确想要监视的描述符fd,以何种形式去监视struct epoll_event {uint32_t     events;    /* 在poll_ctl函数里面,用来确定描述符fd的监视方式 */EPOLLIN :监视描述符是否可读EPOLLOUT:监视描述符是否可写epoll_data_t data;     };typedef union epoll_data {void    *ptr;int      fd;    /* 要求和epoll_ctl函数里面第3个参数fd写的一模一样 */uint32_t u32;uint64_t u64;} epoll_data_t;

epoll完整代码 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <sys/socket.h>typedef struct sockaddr_in addr_in_t;int main(int argc, const char *argv[]) {if (argc != 2) {printf("请输入端口号\n");return 1;}int port = atoi(argv[1]);int server = socket(AF_INET, SOCK_STREAM, 0);if (server == -1) {perror("socket");return 1;}addr_in_t addr = {0};addr.sin_family = AF_INET;addr.sin_port = htons(port);addr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 或者使用其他有效的IP地址if (bind(server, (struct sockaddr*)&addr, sizeof(addr)) == -1) {perror("bind");return 1;}// 监听listen(server, 10);// 创建一个可动态扩容的epoll文件描述符int epfd = epoll_create1(EPOLL_CLOEXEC);if (epfd == -1) {perror("epoll_create1");return 1;}// 将server和stdin添加到epfd里面去struct epoll_event server_event, stdin_event;server_event.data.fd = server;server_event.events = EPOLLIN;stdin_event.data.fd = 0;stdin_event.events = EPOLLIN;if (epoll_ctl(epfd, EPOLL_CTL_ADD, server, &server_event) == -1) {perror("epoll_ctl for server");return 1;}if (epoll_ctl(epfd, EPOLL_CTL_ADD, 0, &stdin_event) == -1) {perror("epoll_ctl for stdin");return 1;}int fd_count = 50; // 这个变量似乎没有被后续代码使用while (1) {struct epoll_event active_fds[50] = {0};int len = epoll_wait(epfd, active_fds, 50, -1);if (len == -1) {perror("epoll_wait");return 1;}// 经过epoll_wait说明有len个描述符激活了for (int i = 0; i < len; i++) {int sock = active_fds[i].data.fd;if (sock == server) {// 激活的是服务器printf("有新客户端连接\n");int client = accept(server, NULL, NULL);if (client == -1) {perror("accept");continue;}struct epoll_event client_event;client_event.data.fd = client;client_event.events = EPOLLIN;if (epoll_ctl(epfd, EPOLL_CTL_ADD, client, &client_event) == -1) {perror("epoll_ctl for client");close(client);continue;}} else if (sock == 0) {// 激活的是标准输入流char buf[64] = {0};scanf("%63s", buf);while (getchar() != '\n'); // 清除输入缓冲区printf("键盘输入了:%s\n", buf);} else {// 激活的不是上面两个,只能是客户端了char buf[64] = {0};int res = read(sock, buf, 64);if (res == 0) {// 客户端断开连接printf("客户端断开连接\n");epoll_ctl(epfd, EPOLL_CTL_DEL, sock, NULL);close(sock);} else {printf("客户端发来消息:%s\n", buf);}}}}return 0;
}

 3.客户端测试代码

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <wait.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/un.h>typedef struct sockaddr_in addr_in_t;
typedef struct sockaddr addr_t;
typedef struct sockaddr_un addr_un_t;enum Type{TYPE_REGIST,TYPE_LOGIN
};typedef struct Pack{int size;// 用来记录整个协议包的实际大小,占4字节enum Type type;// 占4个字节char buf[2048];// 占count个字节int count; // 用来记录指针的偏移量,也就是buf使用了多少个字节
}pack_t;void append(pack_t* pack,const char* data){char* buf = pack->buf;int len = strlen(data);*(short*)(buf+pack->count) = len; // 将buf的前2个字节当做short来存储数据len// memcpy(buf,&len,2);pack->count += 2;memcpy(buf+pack->count,data,len);pack->count += len;pack->size = pack->count + 8;
}int main(int argc, const char *argv[])
{if(argc != 2){printf("请输入端口号\n");return 1;}// ./server 8888int port = atoi(argv[1]);// 将字符串 8888 转换成int类型portint client = socket(AF_INET,SOCK_STREAM,0);addr_in_t addr = {0};addr.sin_family = AF_INET;addr.sin_port = htons(port);addr.sin_addr.s_addr = inet_addr("192.168.60.77");if(connect(client,(addr_t*)&addr,sizeof(addr)) == -1){perror("connect");return 1;}while(1){pack_t pack = {0};pack.type = TYPE_LOGIN;char name[20] = "";char pswd[20] = "";printf("请输入账号:");scanf("%19s",name);while(getchar()!=10);printf("请输入密码:");scanf("%19s",pswd);while(getchar()!=10);// 将name 和 pswd// 按照之前说好的方式(前2个字节记录数据长度n,紧接着的n个字节记录数据本身)将name和pswd存入 pack.buf 里面去// 其实就是 把 name 和 pswd 按照既定格式,添加进入协议包append(&pack,name);append(&pack,pswd);// 当协议包里面拥有name和pswd之后,就可以将协议包发送给服务器了write(client,&pack,pack.size);// 协议包总共占据 pack.count + 4字节,pack.count的长度,根据 name 和 pswd 的长度动态决定}return 0;
}

 

关键字:深圳外贸公司名单_站长百度_做百度推广的网络公司广州_付费内容网站

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: