当前位置: 首页 > news >正文

网站建设昆明网络公司/枸橼酸西地那非片

网站建设昆明网络公司,枸橼酸西地那非片,17173网游排行榜,深圳福田区住房和建设局网站官网用来练手熟悉Linux C/C编程的小服务器,只有一个文件。由于重心在熟悉Linux相关函数上,所以写的很简陋。 开发环境:Ubuntu 18.04.1 LTS 个人的腾讯云服务器 运行方法:直接将cpp文件编译运行即可,运行时需要提供服务器i…

用来练手熟悉Linux C/C++编程的小服务器,只有一个文件。由于重心在熟悉Linux相关函数上,所以写的很简陋。

开发环境:Ubuntu 18.04.1 LTS 个人的腾讯云服务器
运行方法:直接将cpp文件编译运行即可,运行时需要提供服务器ip和port

主要涉及信号、Epoll等基础知识点
最重要的是:win10的telnet是每次实时发送字符(这与ubuntu是不同的),所以我在服务器端添加了string同时如果检测到telnet发送了长度为2的"\r\n"(这是win系统中换行字符),就从对应string里拿出相应积累的字符串并将其输出到其他用户终端上。所以这个程序的客户端telnet不能是linux系统下的telnet服务。

源代码如下

//code1.cpp//用于一对一聊天的程序
//Ubuntu 18.04.1 LTS
//客户端要求:Win10原装telnet程序即可
//win10 cmd 命令: telnet 服务器ip 服务器指定端口#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<assert.h>
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
#include<sys/sendfile.h>
// #include<sys/uio.h>
// #include<sys/stat.h>
// #include<sys/types.h>
#include<fcntl.h>
// #include<pthread.h>
#include<sys/epoll.h>
// #include<sys/wait.h>
// #include<sys/mman.h>
#include<signal.h>
#include<string>
using namespace std;/* 通过缓存消息依次分发的方式进行管理 */
/* epoll进行IO复用 采用统一信号管道 */
/* 发送方采用win10 telnet单字节发送 单行消息的结束符号识别为"\r\n" */class UserInfo{
public://构造函数UserInfo():fd(-1){};//初始化void init(int fd){this->fd=fd;this->buffer="";};//清除void clear(){this->fd=-1;this->buffer="";};//用户文件描述符int fd;//用户缓冲区string buffer;
};/* 全局变量 *///缓存区大小
const int BUFFER_SIZE = 1024;
//epoll列表大小
const int MAX_EPOLL_NUMBER = 10;
//backlog值
const int BACKLOG = 5;
//最大接入用户数量
const int MAX_USER_NUM = 2;//当前在线用户数量 <=2
int cur_user_num = 0;
//当前在线用户的信息
UserInfo users[MAX_USER_NUM];//统一信号管道 所有信号 => sig_pipefd[1] ==> sig_pipefd[0]
int sig_pipefd[2];/* 预备函数 *///自定义信号处理函数
void handler(int sig){int save_errno = errno;int msg = sig;send(sig_pipefd[1],(void*)&msg,1,0);errno = save_errno;
}//添加信号
void addsig(int sig,void(handler)(int)){struct sigaction sa;memset(&sa,0,sizeof(sa));sa.sa_flags |= SA_RESTART;sigfillset(&sa.sa_mask);sa.sa_handler = handler;assert( sigaction(sig,&sa,NULL) != -1 );
}//记录客户端文件描述符 成功0 超量失败-1
int adduserfd(int fd){//使用前最好先检查当前在线用户数量if(cur_user_num == MAX_USER_NUM)return -1;for(int i=0;i<MAX_USER_NUM;++i){if(users[i].fd == -1){users[i].init(fd);cur_user_num++;return 0;}}return -1;
}//从客户端文件描述符记录表中删除指定的fd 成功0 没有找到失败-1
int deluserfd(int fd){//使用前最好先确保fd是有效的在线用户的文件描述符for(int i=0;i<MAX_USER_NUM;++i){if(users[i].fd == fd){users[i].clear();cur_user_num--;return 0;}}return -1;
}//向fd指定的客户链接添加char*t指定的长度为len的字符串
int addCharsTofd(int fd,char* t,int len){for(int i=0;i<MAX_USER_NUM;++i){if(users[i].fd == fd){for(int k=0;k<len;++k)users[i].buffer+=t[k];return 0;}}return -1;
}//获取并销毁fd中目前存储的数据
int getCharsfromfd(int fd,string& Chars){for(int i=0;i<MAX_USER_NUM;++i){if(users[i].fd == fd){Chars = users[i].buffer;users[i].buffer = "";return 0;}}return -1;
}//设置文件描述符非阻塞
int setnonblocking(int fd){int old_option = fcntl(fd,F_GETFL);int new_option = old_option | O_NONBLOCK;fcntl(fd,F_SETFL,new_option);return old_option;
}//向epollfd中注册文件描述符fd(非阻塞)
void addfd(int epollfd,int fd){epoll_event event;bzero(&event,sizeof(event));event.data.fd = fd;event.events = EPOLLIN | EPOLLET;epoll_ctl(epollfd,EPOLL_CTL_ADD,fd,&event);setnonblocking(fd);
}//向fd客户端发送来自服务器的系统消息
void sendSysMsg(int fd,const char* msg){string line = string("ServerMsg:[") + string(msg) + string("]\r\n");int len = line.size();char* buf = new char[len+10];memcpy(buf,line.c_str(),line.size());buf[line.size()] = '\0';printf("SendSysMsgtoUserfd[%d]: %s",fd,buf);send(fd,buf,strlen(buf),0);delete[] buf;
}//向在线的所有用户广播系统消息
void allSendSysMsg(const char* msg){string line = string("ServerMsg:[") + string(msg) + string("]\r\n");int len = line.size();char* buf = new char[len+10];memcpy(buf,line.c_str(),line.size());buf[line.size()] = '\0';int msgLenth = strlen(buf);printf("SendSysMsgforAllUsers: %s",buf);//向全员发送系统消息for(int i=0;i<MAX_USER_NUM;++i){if(users[i].fd != -1){send(users[i].fd,buf,msgLenth,0);}}delete[] buf;
}//删除epollfd中对fd文件描述符的监听
void delfd(int epollfd,int fd){epoll_event event;bzero(&event,sizeof(event));event.data.fd = fd;event.events = EPOLLIN | EPOLLET;epoll_ctl(epollfd,EPOLL_CTL_DEL,fd,&event);
}//从fd获取消息并发送到其他在线用户中
int sendMsgFromfd(int msgfd){string msg = "";if(getCharsfromfd(msgfd,msg) == -1)return -1;//构建缓冲消息string beifen = msg;msg += "\r\n";//补齐win版本换行符char* buf = new char[msg.size() + 4];memset(buf,0,sizeof(buf));memcpy(buf,msg.c_str(),msg.size());//分发消息for(int k=0;k<MAX_USER_NUM;++k){if( users[k].fd != -1 && users[k].fd != msgfd ){send(users[k].fd,buf,strlen(buf),0);}}delete[] buf;printf("[sockfd]:%d send [MSG]:%s\n",msgfd,beifen.c_str());return 0;
}//核心程序
int main(int argc,char* argv[]){if(argc <= 2){printf("usage: %s ip_address port\n",basename(argv[0]));return 1;}//初始化服务器参数printf("Init Server System...\n");const char* ip = argv[1];int port = atoi(argv[2]);int ret = -1;sockaddr_in address;bzero(&address,sizeof(address));address.sin_family = AF_INET;inet_pton(AF_INET,ip,&address.sin_addr);address.sin_port = htons(port);int listenfd = socket(AF_INET,SOCK_STREAM,0);assert(listenfd >= 0);ret = bind(listenfd,(struct sockaddr*)&address,sizeof(address));assert(ret != -1);ret = listen(listenfd,BACKLOG);assert(ret != -1);//初始化全双工管道printf("Init Pipe...\n");ret = socketpair(PF_UNIX,SOCK_STREAM,0,sig_pipefd);assert(ret != -1);setnonblocking(sig_pipefd[1]);//设置管道非阻塞//初始化epoll内核表printf("Init Epoll...\n");int epollfd = epoll_create(MAX_EPOLL_NUMBER);assert(epollfd >= 0);//epoll内核监听注册addfd(epollfd,listenfd);//注册epoll对listenfd的监听addfd(epollfd,sig_pipefd[0]);//注册epoll对信号管道0端的监听//设置信号处理printf("Init Signals...\n");addsig(SIGTERM,handler);addsig(SIGINT,handler);addsig(SIGCHLD,handler);addsig(SIGPIPE,SIG_IGN);//核心循环bool m_stop = false;epoll_event events[MAX_EPOLL_NUMBER];printf("Server Running..\n");while(!m_stop){int number = epoll_wait(epollfd,events,MAX_EPOLL_NUMBER,-1);printf("epoll number == %d\n",number);if( (number < 0) && (errno != EINTR) ){printf("epoll error\n");break;}//循环检测事件for(int i=0;i<number;++i){int sockfd = events[i].data.fd;if( (sockfd == listenfd) && (events[i].events & EPOLLIN) ){//新的客户链接需要接入sockaddr_in client_address;socklen_t client_length = sizeof(client_address);int client_fd = accept(sockfd,(struct sockaddr*)&client_address,&client_length);if(client_fd < 0){printf("accept error [fd %d] [errno %d]\n",client_fd,errno);continue;}//注册新用户信息ret = adduserfd(client_fd);if(ret == -1){//用户已满无法注册登录const char* nolink = "Sorry Full in Chating.\r\n";send(client_fd,nolink,strlen(nolink),0);close(client_fd);printf("One User Get into Link but Failed for Full\n");continue;}printf("One User Get into Link\n");//注册关于client_fd的监听addfd(epollfd,client_fd);//发送系统消息sendSysMsg(client_fd,"Welcome to ChatServer Based on TELNET");//向其他用户发送新用户消息for(int k=0;k<MAX_USER_NUM;++k){int aim = users[k].fd;if(aim != -1 && aim != client_fd){sendSysMsg(aim,"One User Get into Server");}}}else if( (sockfd == sig_pipefd[0]) && (events[i].events & EPOLLIN) ){//存在信号通知char signals[100];memset(signals,0,sizeof(signals));ret = recv(sockfd,signals,100,0);printf("Get Signals Num is %d\n",ret);//处理信号for(int k=0;k<ret;++k){switch(signals[k]){case SIGCHLD:{printf("SIG:[SIGCHLD]\n");break;}case SIGTERM:case SIGINT:{if(signals[k] == SIGTERM) printf("sig:[SIGTERM]\n");else printf("sig:[SIGINT]\n");m_stop = true;break;}default:break;}}}else if( events[i].events & EPOLLIN ){//存在输入事件char buf[BUFFER_SIZE];memset(buf,0,sizeof(buf));ret = recv(sockfd,buf,BUFFER_SIZE-1,0);printf("msg recv() len == %d\n",ret);if(ret < 0){if(errno != EAGAIN){//断开客户端sockfd的连接deluserfd(sockfd);delfd(epollfd,sockfd);close(sockfd);allSendSysMsg("One User Left Just Now");printf("link break for recv()<0\n");}}else if(ret == 0){//断开客户端sockfd的连接deluserfd(sockfd);delfd(epollfd,sockfd);close(sockfd);allSendSysMsg("One User Left Just Now");printf("link break for recv()==0\n");}else{//主业务逻辑if(ret == 2 && buf[0] == '\r' && buf[1] == '\n'){//向其他用户发送消息sendMsgFromfd(sockfd);}else{//添加字符串到缓存addCharsTofd(sockfd,buf,ret);}}}else{continue;}}//for}//while//关闭所有仍在线的客户端链接for(int i=0;i<MAX_USER_NUM;++i){if(users[i].fd != -1){int fd = users[i].fd;sendSysMsg(fd,"Chat Server's System Exit");users[i].clear();delfd(epollfd,fd);close(fd);}}close(listenfd);close(epollfd);close(sig_pipefd[0]);close(sig_pipefd[1]);printf("System Exit\n");return 0;
}// g++ code1.cpp -o code1
// ./code1 172.17.0.6 12345
// g++ code1.cpp -o code1 && ./code1 172.17.0.6 12345

头文件有冗余,可以筛选一下,已经注释掉了一部分没用的头文件。注意Linux与Win在换行上的差异。

http://www.jmfq.cn/news/4744531.html

相关文章:

  • 网站建设网站模板/网站排名优化手机
  • h5 网站模板/交换友情链接吧
  • 普陀大型网站建设/关键词优化排名用哪些软件比较好
  • 专业做皮草的网站/天津seo排名效果好
  • 软件公司网站源码/巨量数据分析入口
  • 网站建设基础问题/怎样做网站推广
  • 潍坊网站建设联系方式/怎么做一个公司网站
  • 蚌山网站建设/河南网站排名优化
  • 深圳罗湖做网站公司哪家好/云seo关键词排名优化软件
  • 北京做网站公司有哪些/下载百度app最新版到桌面
  • 汽车网站建设代理加盟/长沙的seo网络公司
  • 网站推广品牌/北京优化网站方法
  • 个人网站公安局备案/网站搜索排优化怎么做
  • 网站的建设过程/seo线上培训多少钱
  • 有做火币网这种网站的吗/搜图片找原图
  • 那个网站能找到人/seo网站优化软件价格
  • 网站怎么被黑/网络营销手段
  • win xp 个人网站免费建设/网络营销有哪些推广方法
  • 电子商务网站设计规划书/服务器
  • 武汉网站建设索q.479185700/百度正版下载并安装
  • 成都网站建设网站建设哪家好/广州百度推广外包
  • 佛山制作网站公司推荐/最新网络营销方式有哪些
  • 网站两侧固定广告代码/宁德市人民政府
  • 石家庄制作网站的公司哪家好/百度知道下载安装
  • 咖啡网站设计模板/网站app免费生成软件
  • wordpress多媒体路径/百度搜索引擎优化
  • 做视频网站推广挣钱吗/网站怎么注册
  • 网站开发流程主要分成什么/爱站工具包官网
  • wordpress容易被黑吗/什么是网站seo
  • 电脑网站怎么创建到桌面上/百度seo教程视频