Linux 网络编程八(epoll应用--大并发处理)

http://www.cnblogs.com/zhanggaofeng/p/5901316.html

复制代码
//头文件 pub.h
#ifndef _vsucess#define _vsucess#ifdef __cplusplus
extern "C"
{#endif
//服务器创建socket
int server_socket(int port);//设置非阻塞
int setnonblock(int st);//接收客户端socket
int server_accept(int st);//关闭socket
int close_socket(int st);//接收消息
int socket_recv(int st);//连接服务器
int connect_server(char *ipaddr,int port);//发送消息
int socket_send(int st);//将sockaddr_in转化成IP地址
int sockaddr_toa(const struct sockaddr_in * addr, char * ipaddr);#ifdef __cplusplus
}
#endif#endif
复制代码
复制代码
//辅助方法--pub.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>//htons()函数头文件
#include <netinet/in.h>//inet_addr()头文件
#include <fcntl.h>
#include "pub.h"#define MAXBUF 1024//创建socket
int socket_create()
{int st = socket(AF_INET, SOCK_STREAM, 0);if (st == -1){printf("create socket failed ! error message :%s\n", strerror(errno));return -1;}return st;
}//设置服务端socket地址重用
int socket_reuseaddr(int st)
{int on = 1;if (setsockopt(st, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1){printf("setsockopt reuseaddr failed ! error message :%s\n",strerror(errno));//close socket
        close_socket(st);return -1;}return 0;
}//服务器绑定--监听端口号
int socket_bind(int st, int port)
{struct sockaddr_in addr;memset(&addr, 0, sizeof(addr));//typeaddr.sin_family = AF_INET;//portaddr.sin_port = htons(port);//ipaddr.sin_addr.s_addr = htonl(INADDR_ANY);//bind ip addressif (bind(st, (struct sockaddr *) &addr, sizeof(addr)) == -1){printf("bind failed ! error message :%s\n", strerror(errno));//close socket
        close_socket(st);return -1;}//listenif (listen(st, 20) == -1){printf("listen failed ! error message :%s\n", strerror(errno));//close socket
        close_socket(st);return -1;}return 0;
}//服务器创建socket
int server_socket(int port)
{if (port < 0){printf("function server_socket param not correct !\n");return -1;}//create socketint st = socket_create();if (st < 0){return -1;}//reuseaddrif (socket_reuseaddr(st) < 0){return -1;}//bind and listenif (socket_bind(st, port) < 0){return -1;}return st;
}//连接服务器
int connect_server(char *ipaddr,int port)
{if(port<0||ipaddr==NULL){printf("function connect_server param not correct !\n");return -1;}int st=socket_create();if(st<0){return -1;}//conect serverstruct sockaddr_in addr;memset(&addr,0,sizeof(addr));addr.sin_family=AF_INET;addr.sin_port=htons(port);addr.sin_addr.s_addr=inet_addr(ipaddr);if(connect(st,(struct sockaddr *)&addr,sizeof(addr))==-1){printf("connect failed ! error message :%s\n",strerror(errno));return -1;}return st;
}//设置非阻塞
int setnonblock(int st)
{if (st < 0){printf("function setnonblock param not correct !\n");//close socket
        close_socket(st);return -1;}int opts = fcntl(st, F_GETFL);if (opts < 0){printf("func fcntl failed ! error message :%s\n", strerror(errno));return -1;}opts = opts | O_NONBLOCK;if (fcntl(st, F_SETFL, opts) < 0){printf("func fcntl failed ! error message :%s\n", strerror(errno));return -1;}return opts;
}//接收客户端socket
int server_accept(int st)
{if (st < 0){printf("function accept_clientsocket param not correct !\n");return -1;}struct sockaddr_in addr;memset(&addr, 0, sizeof(addr));socklen_t len = sizeof(addr);int client_st = accept(st, (struct sockaddr *) &addr, &len);if (client_st < 0){printf("accept client failed ! error message :%s\n", strerror(errno));return -1;} else{char ipaddr[20] = { 0 };sockaddr_toa(&addr, ipaddr);printf("accept by %s\n", ipaddr);}return client_st;
}//关闭socket
int close_socket(int st)
{if (st < 0){printf("function close_socket param not correct !\n");return -1;}close(st);return 0;
}//将sockaddr_in转化成IP地址
int sockaddr_toa(const struct sockaddr_in * addr, char * ipaddr)
{if (addr == NULL || ipaddr == NULL){return -1;}unsigned char *p = (unsigned char *) &(addr->sin_addr.s_addr);sprintf(ipaddr, "%u.%u.%u.%u", p[0], p[1], p[2], p[3]);return 0;
}//接收消息
int socket_recv(int st)
{if (st < 0){printf("function socket_recv param not correct !\n");return -1;}char buf[MAXBUF] = { 0 };int rc=0;rc=recv(st,buf,sizeof(buf),0);if(rc==0){printf("client is close ! \n");return -1;}else if(rc<0){/** recv错误信息:Connection reset by peer* 错误原因:服务端给客户端发送数据,但是客户端没有接收,直接关闭,那么就会报错* 如果客户端接受了数据,再关闭,也不会报错,rc==0.*/printf("recv failed ! error message :%s \n",strerror(errno));return -1;}printf("%s",buf);//send message/*memset(buf,0,sizeof(buf));strcpy(buf,"i am server , i have recved !\n");if(send(st,buf,strlen(buf),0)<0){printf("send failed ! error message :%s \n",strerror(errno));return -1;}*/return 0;
}//发送消息
int socket_send(int st)
{char buf[MAXBUF]={0};while(1){//read from keyboardread(STDIN_FILENO,buf,sizeof(buf));if(buf[0]=='0'){break;}if(send(st,buf,strlen(buf),0)<0){printf("send failed ! error message :%s \n",strerror(errno));return -1;}memset(buf,0,sizeof(buf));}return 0;
}
复制代码
复制代码
//网络编程服务端
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>//htons()函数头文件
#include <netinet/in.h>//inet_addr()头文件
#include <fcntl.h>
#include <sys/epoll.h>
#include "pub.h"#define MAXSOCKET 20int main(int arg, char *args[])
{if (arg < 2){printf("please print one param!\n");return -1;}//create server socketint listen_st = server_socket(atoi(args[1]));if (listen_st < 0){return -1;}/** 声明epoll_event结构体变量ev,变量ev用于注册事件,* 数组events用于回传需要处理的事件*/struct epoll_event ev, events[100];//生成用于处理accept的epoll专用文件描述符int epfd = epoll_create(MAXSOCKET);//把socket设置成非阻塞方式
    setnonblock(listen_st);//设置需要放到epoll池里的文件描述符ev.data.fd = listen_st;//设置这个文件描述符需要epoll监控的事件/** EPOLLIN代表文件描述符读事件*accept,recv都是读事件*/ev.events = EPOLLIN | EPOLLERR | EPOLLHUP;/** 注册epoll事件* 函数epoll_ctl中&ev参数表示需要epoll监视的listen_st这个socket中的一些事件*/epoll_ctl(epfd, EPOLL_CTL_ADD, listen_st, &ev);while (1){/** 等待epoll池中的socket发生事件,这里一般设置为阻塞的* events这个参数的类型是epoll_event类型的数组* 如果epoll池中的一个或者多个socket发生事件,* epoll_wait就会返回,参数events中存放了发生事件的socket和这个socket所发生的事件* 这里强调一点,epoll池存放的是一个个socket,不是一个个socket事件* 一个socket可能有多个事件,epoll_wait返回的是有消息的socket的数目* 如果epoll_wait返回事件数组后,下面的程序代码却没有处理当前socket发生的事件* 那么epoll_wait将不会再次阻塞,而是直接返回,参数events里面的就是刚才那个socket没有被处理的事件*/int nfds = epoll_wait(epfd, events, MAXSOCKET, -1);if (nfds == -1){printf("epoll_wait failed ! error message :%s \n", strerror(errno));break;}int i = 0;for (; i < nfds; i++){if (events[i].data.fd < 0)continue;if (events[i].data.fd == listen_st){//接收客户端socketint client_st = server_accept(listen_st);/** 监测到一个用户的socket连接到服务器listen_st绑定的端口**/if (client_st < 0){continue;}//设置客户端socket非阻塞
                setnonblock(client_st);//将客户端socket加入到epoll池中struct epoll_event client_ev;client_ev.data.fd = client_st;client_ev.events = EPOLLIN | EPOLLERR | EPOLLHUP;epoll_ctl(epfd, EPOLL_CTL_ADD, client_st, &client_ev);/** 注释:当epoll池中listen_st这个服务器socket有消息的时候* 只可能是来自客户端的连接消息* recv,send使用的都是客户端的socket,不会向listen_st发送消息的*/continue;}//客户端有事件到达if (events[i].events & EPOLLIN){//表示服务器这边的client_st接收到消息if (socket_recv(events[i].data.fd) < 0){close_socket(events[i].data.fd);//接收数据出错或者客户端已经关闭events[i].data.fd = -1;/*这里continue是因为客户端socket已经被关闭了,* 但是这个socket可能还有其他的事件,会继续执行其他的事件,* 但是这个socket已经被设置成-1* 所以后面的close_socket()函数都会报错*/continue;}/** 此处不能continue,因为每个socket都可能有多个事件同时发送到服务器端* 这也是下面语句用if而不是if-else的原因,*/}//客户端有事件到达if (events[i].events & EPOLLERR){printf("EPOLLERR\n");//返回出错事件,关闭socket,清理epoll池,当关闭socket并且events[i].data.fd=-1,epoll会自动将该socket从池中清除
                close_socket(events[i].data.fd);events[i].data.fd = -1;continue;}//客户端有事件到达if (events[i].events & EPOLLHUP){printf("EPOLLHUP\n");//返回挂起事件,关闭socket,清理epoll池
                close_socket(events[i].data.fd);events[i].data.fd = -1;continue;}}}//close epoll
    close(epfd);//close server socket
    close_socket(listen_st);return 0;
}
复制代码
复制代码
//网络编程客户端
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>//htons()函数头文件
#include <netinet/in.h>//inet_addr()头文件
#include <fcntl.h>
#include <sys/epoll.h>
#include "pub.h"int main(int arg,char *args[])
{if(arg<2){printf("please print two param !\n");}//端口号int port=atoi(args[2]);//服务端IP地址char ipaddr[30]={0};strcpy(ipaddr,args[1]);//connect serverint st=connect_server(ipaddr,port);//send message//发送消息--
    socket_send(st);//close socket
    close(st);return 0;
}
复制代码
复制代码
.SUFFIXES:.c .o
CC=gcc
SRCS1=epoll_client.c\pub.c
SRCS2=epoll_server.c\pub.c
OBJS1=$(SRCS1:.c=.o)
OBJS2=$(SRCS2:.c=.o)
EXEC1=mclient
EXEC2=mserverstart:$(OBJS1) $(OBJS2)$(CC) -o $(EXEC1) $(OBJS1)$(CC) -o $(EXEC2) $(OBJS2)@echo "-------ok-----------"
.c.o:$(CC) -Wall -g -o $@ -c $<
clean:rm -f $(OBJS1)rm -f $(EXEC1)rm -f $(OBJS2)rm -f $(EXEC2)
复制代码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/383912.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【数据结构与算法】内部排序之三:堆排序(含完整源码)

转载请注明出处&#xff1a;http://blog.csdn.net/ns_code/article/details/20227303 前言 堆排序、快速排序、归并排序&#xff08;下篇会写这两种排序算法&#xff09;的平均时间复杂度都为O&#xff08;n*logn&#xff09;。要弄清楚堆排序&#xff0c;就要先了解下二叉堆这…

模线性方程(中国剩余定理+扩展中国剩余定理)

已知一系列除数和模数,求最小的满足条件的数 我们先考虑一般的情况&#xff0c;即模数不互质。&#xff08;扩展中国剩余定理&#xff09; 我们考虑两个方程的情况 x%MR xk1∗MRxk1 * MRxk1∗MR x%mr xk2∗mrxk2 * mrxk2∗mr 所以k1∗MRk2∗mrk1 * MRk2 * mrk1∗MRk2∗mr 即…

【数据结构】(面试题)使用两个栈实现一个队列(详细介绍)

http://blog.csdn.net/hanjing_1995/article/details/51539578 使用两个栈实现一个队列 思路一&#xff1a; 我们设定s1是入栈的&#xff0c;s2是出栈的。 入队列&#xff0c;直接压到s1即可 出队列&#xff0c;先把s1中的元素倒入到s2中&#xff0c;弹出s2中的栈顶元素&#x…

C++::探索对象模型

前面我们已经知道, 在没有虚函数的时候, 对象的大小就是对应的成员变量的大小, 而成员函数不会占用对象的空间, 今天我们来讨论一下, 当类中定义了虚函数的时候, 此时对象的大小以及对象模型 非继承下的对象模型 class Base { public:virtual void func1(){cout << &qu…

软件测试相关概念

什么叫软件测试 软件测试就是测试产品没有错误,同时又证明软件是可以正确运行的 测试和调试的区别 调试一般都在开发期间 ,测试是伴随着整个软件的生命周期, 调试是发现程序中问题并且解决问题, 测试是发现程序中的缺陷 软件测试的目的和原则 目的:验证软件有没有问题 原…

C++静态成员函数访问非静态成员的几种方法

https://www.cnblogs.com/rickyk/p/4238380.html 大家都知道C中类的成员函数默认都提供了this指针&#xff0c;在非静态成员函数中当你调用函数的时候&#xff0c;编译器都会“自动”帮你把这个this指针加到函数形参里去。当然在C灵活性下面&#xff0c;类还具备了静态成员和静…

HDU2683——欧拉完全数

题目要求符合等式的数&#xff0c;我们首先要做的就是分析这个数&#xff1a; 对于这个等式&#xff0c;我们可能什么都看不出来&#xff0c;左边很难化简的样子&#xff0c;所以我们就要想到通过变化怎么样把右边化成和左边形式差不多的样子。结合组合数我们想到二项式定理&am…

获取网络接口信息——ioctl()函数与结构体struct ifreq、 struct ifconf

http://blog.csdn.net/windeal3203/article/details/39320605 Linux 下 可以使用ioctl()函数 以及 结构体 struct ifreq 结构体struct ifconf来获取网络接口的各种信息。 ioctl 首先看ioctl()用法ioctl()原型如下&#xff1a;#include <sys/ioctl.h>int ioctl(int fd, i…

java中引用传递

基本概念 栈内存 所谓的栈内存就是存储进程在运行过程中变量的内存空间 堆内存 所谓的堆内存就是存储系统中数据的内存空间 数组相关的引用传递 先来看一段代码 public class ArrayDemo {public static void main(String[] args) {int[] x null;x new int[3];System.o…

(原创)C++11改进我们的程序之右值引用

http://www.cnblogs.com/qicosmos/p/3369940.html 本次主要讲c11中的右值引用&#xff0c;后面还会讲到右值引用如何结合std::move优化我们的程序。 c11增加了一个新的类型&#xff0c;称作右值引用(R-value reference)&#xff0c;标记为T &&&#xff0c;说到右值引用…

(原创)C++11改进我们的程序之move和完美转发

http://www.cnblogs.com/qicosmos/p/3376241.html 本次要讲的是右值引用相关的几个函数&#xff1a;std::move, std::forward和成员的emplace_back&#xff0c;通过这些函数我们可以避免不必要的拷贝&#xff0c;提高程序性能。move是将对象的状态或者所有权从一个对象转移到另…

微型个人博客服务器

Http相关简介 Http是应用层的基于请求响应的一个协议, 其中Http的请求响应可以分为四部分. 请求行, 请求报头,空行, 请求正文.其中请求行包括了请求方法, url, 版本号, 请求报头包括请求属性, 冒分割的键值对, 每组属性之间都以换行的形式分开, 最后一空行作为请求的结束标识.…

[C/C++]关于C++11中的std::move和std::forward

http://blog.sina.com.cn/s/blog_53b7ddf00101p5t0.htmlstd::move是一个用于提示优化的函数&#xff0c;过去的c98中&#xff0c;由于无法将作为右值的临时变量从左值当中区别出来&#xff0c;所以程序运行时有大量临时变量白白的创建后又立刻销毁&#xff0c;其中又尤其是返回…

Linux I/O复用之select函数详解

http://blog.csdn.net/y396397735/article/details/55004775 select函数的功能和调用顺序 使用select函数时统一监视多个文件描述符的&#xff1a; 1、 是否存在套接字接收数据&#xff1f; 2、 无需阻塞传输数据的套接字有哪些? 3、 哪些套接字发生了异常&#xff1f; sel…

深入研究socket编程(3)——使用select函数编写客户端和服务器

http://blog.csdn.net/chenxun_2010/article/details/50488394 首先看原先《UNIX网络编程——并发服务器&#xff08;TCP&#xff09;》的代码&#xff0c;服务器代码serv.c&#xff1a; [cpp] view plaincopy #include<stdio.h> #include<sys/types.h> #inclu…

Ubuntu安装搭建Clion环境

呜呜呜&#xff0c;太辛苦了&#xff0c;我终于安装好这个了。 大概过程就是先在官网下载安装包&#xff0c;然后解压以后用终端移动到对应文件夹下运行clin.sh 运行完以后会有一些窗口&#xff0c;第一个选择don’t~~&#xff0c;然后点击ok 接受&#xff08;你可以不接受…

UNIX网络编程——select函数的并发限制和 poll 函数应用举例

http://blog.csdn.net/chenxun_2010/article/details/50489577 一、用select实现的并发服务器&#xff0c;能达到的并发数&#xff0c;受两方面限制 1、一个进程能打开的最大文件描述符限制。这可以通过调整内核参数。可以通过ulimit -n来调整或者使用setrlimit函数设置&#x…

【Java学习笔记二】继承和多态

与C不同的是&#xff0c;在Java中&#xff0c;一个类只能直接继承另一个类&#xff0c;而不允许继承多个类&#xff0c;这个新类称为继承类、派生类或者子类&#xff0c;而被继承的类称为基类或者父类。 继承类能够继承基类的群不属性和行为。 面向对象程序设计的三大特点为&…

Linux系统编程——线程池

http://blog.csdn.net/tennysonsky/article/details/46490099# 线程池基本原理 在传统服务器结构中&#xff0c;常是有一个总的监听线程监听有没有新的用户连接服务器&#xff0c;每当有一个新的用户进入&#xff0c;服务器就开启一个新的线程用户处理这 个用户的数据包。这个线…

简单Linux C线程池

http://www.cnblogs.com/venow/archive/2012/11/22/2779667.html 大多数的网络服务器&#xff0c;包括Web服务器都具有一个特点&#xff0c;就是单位时间内必须处理数目巨大的连接请求&#xff0c;但是处理时间却是比较短的。在传统的多线程服务器模型中是这样实现的&#xff1…