博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Linux socket多进程服务器框架三
阅读量:6591 次
发布时间:2019-06-24

本文共 5291 字,大约阅读时间需要 17 分钟。

在使用select管理服务器连接的时候:注意1:select是可中断睡眠函数,需要屏蔽信号注意2:必须获取select的返回值nread,每次处理完一个事件,nread需要-1注意3:如果客户端的连接超过连接池的大小,需要关闭客户端连接注意4:获取最大套接字的方法是每次有客户端连接过来时,在和maxfd比较,这样就不用每次select之前都遍历池,查找最大值
服务器
//serhelp.h#ifndef _vxser#define _vxser#ifdef __cplusplusextern "C"{#endif/** * sersocket_init - socket初始化 * @listenfd:文件描述符 * 成功返回0,失败返回错误码 * */int sersocket_init(int *listenfd);/** * listen_socket - 绑定端口号,监听套接字 * @listenfd:文件描述符 * @port:绑定的端口号 * 成功返回0,失败返回错误码 * */int listen_socket(int listenfd, int port);/** * run_server - 运行服务器 * @listenfd:文件描述符 * */void run_server(int listenfd);#ifdef __cplusplusextern "C"}#endif#endif
//serhelp.c#include 
#include
#include
#include
#include
#include
/* See NOTES */#include
#include
#include
#include
#include
#include "commsocket.h"/** * sersocket_init - socket初始化 * @listenfd:文件描述符 * 成功返回0,失败返回错误码 * */int sersocket_init(int *listenfd){ int ret = 0; if (listenfd == NULL) { ret = Sck_ParamErr; printf("sersocket_init() params not correct !\n"); return ret; } //初始化socket环境 int fd = socket(AF_INET, SOCK_STREAM, 0); if (fd == -1) { ret = Sck_BaseErr; perror("socket() err"); return ret; } *listenfd = fd; return ret;}/** * listen_socket - 绑定端口号,监听套接字 * @listenfd:文件描述符 * @port:绑定的端口号 * 成功返回0,失败返回错误码 * */int listen_socket(int listenfd, int port){ int ret = 0; if (listenfd < 0 || port < 0 || port > 65535) { ret = Sck_ParamErr; printf("listen_socket() params not correct !\n"); return ret; } //reuse addr int optval = 1; ret = setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); if (ret == -1) { ret = Sck_BaseErr; perror("setsockopt() err"); return ret; } //bind struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = inet_addr("127.0.0.1"); ret = bind(listenfd, (struct sockaddr *) &addr, sizeof(addr)); if (ret == -1) { ret = Sck_BaseErr; perror("bind() err"); return ret; } //listen ret = listen(listenfd, SOMAXCONN); if (ret == -1) { ret = Sck_BaseErr; perror("listen() err"); return ret; } return ret;}/** * handler - 信号捕捉函数 * @sign:信号码 * */void handler(int sign){ if (sign == SIGPIPE) { printf("server accept SIGPIPE !\n"); }}/** * run_server - 运行服务器 * @listenfd:文件描述符 * */void run_server(int listenfd){ int ret = 0; //屏蔽SIGPIPIE信号 if (signal(SIGPIPE, handler) == SIG_ERR) { printf("signal() failed !\n"); return; } //定义文件描述符集合 fd_set allsets; FD_ZERO(&allsets); fd_set readfds; FD_ZERO(&readfds); //定义客户端套接字池 char socketPond[128] = { 0 }; int i = 0; for (i = 0; i < 128; i++) { socketPond[i] = -1; } //定义池子最后一个元素的下标 int maxindex = 0; //定义文件描述符中值最大的fd int maxfd = listenfd; //将监听套接字加入到集合中 FD_SET(listenfd, &allsets); struct sockaddr_in peeraddr; socklen_t peerlen = sizeof(struct sockaddr_in); //定义接收缓冲区 char buf[MAXBUFSIZE] = { 0 }; int buflen = 0; int conn = 0; int nread = 0; while (1) { readfds = allsets; do { nread = select(maxfd + 1, &readfds, NULL, NULL, NULL); } while (nread == -1 && errno == EINTR);//屏蔽信号(重点) if (nread == -1) { perror("select() err"); return; } else if (nread == 0) { //超时 continue; } else if (nread > 0) { //执行操作 //1.处理服务器监听套接字 if (FD_ISSET(listenfd, &readfds)) { //客户端有连接完成三次握手 memset(&peeraddr, 0, sizeof(struct sockaddr_in)); peerlen = sizeof(struct sockaddr_in); conn = accept(listenfd, (struct sockaddr *) &peeraddr, &peerlen); if (conn == -1) { perror("accept() err"); break; } printf("accept from %s\n", inet_ntoa(peeraddr.sin_addr)); //将客户端套接字加入池子中 for (i = 0; i < 128; i++) { if (socketPond[i] == -1) { socketPond[i] = conn; //数组最大下标后移 if (maxindex <= i) maxindex = i + 1; break; } } //如果超过最大连接数,直接关闭连接(重点) if (i == 128) { close(conn); continue; } //将客户端套接字加入到监听集合中 FD_SET(conn, &allsets); //每新加一个连接,就更新最大套接字(重点) if(conn>maxfd) maxfd=conn; //需要处理的事件数-1(重点) if (--nread <= 0) continue; } //2.客户端读事件 for (i = 0; i < maxindex; i++) { if (socketPond[i] == -1) continue; if (FD_ISSET(socketPond[i], &readfds)) { //接收客户端信息 memset(buf, 0, sizeof(buf)); buflen = MAXBUFSIZE; ret = socket_recv(socketPond[i], buf, &buflen); if (ret == -1) { //接收信息出错,关闭套接字 close(socketPond[i]); //将该套接字移除池子 socketPond[i] = -1; //将该套接字移除监听集合 FD_CLR(conn, &allsets); } else { //打印信息 fputs(buf, stdout); //向客户端发送数据 ret = socket_send(socketPond[i], buf, buflen); if (ret == -1) { //发送数据出错,关闭套接字 close(socketPond[i]); //将该套接字移除池子 socketPond[i] = -1; //将该套接字移除监听集合 FD_CLR(conn, &allsets); } } //处理的事件数-1 if (--nread <= 0) break; } } } } return;}
//服务器#include "serhelp.h"#include 
#include "commsocket.h"int main(){ int ret = 0; int sockfd = 0; //初始化socket ret = sersocket_init(&sockfd); if (ret != 0) { printf("error message:%s\n", strsockerr(ret)); return -1; } //监听 ret = listen_socket(sockfd, 8080); if (ret != 0) { printf("error message:%s\n", strsockerr(ret)); return -1; } //运行 run_server(sockfd); return 0;}
 
.SUFFIXES:.c .oCC=gccSRCS1=mserver.c\    serhelp.c\    commsocket.c\    sockhelp.cOBJS1=$(SRCS1:.c=.o)EXEC1=mserSRCS2=mclient.c\    clthelp.c\    commsocket.c\    sockhelp.cOBJS2=$(SRCS2:.c=.o)EXEC2=mclstart:$(OBJS1) $(OBJS2)    $(CC) -o $(EXEC1) $(OBJS1)    $(CC) -o $(EXEC2) $(OBJS2)    @echo "--------OK-----------".c.o:    $(CC) -Wall -g -o $@ -c $

 

 

转载地址:http://urdio.baihongyu.com/

你可能感兴趣的文章
【转】cookie如何共享到各个浏览器
查看>>
自制基于HMM的python中文分词器
查看>>
如何在Root的手机上开启ViewServer,使得HierachyViewer能够连接
查看>>
RDIFramework.NET ━ .NET快速信息化系统开发框架 V3.2-新增锁定用户与解除锁定用户的功能...
查看>>
vue1.0 的过滤器
查看>>
如何删除anaconda
查看>>
Mybatis3.3——源码阅读笔记
查看>>
oracle中的trunc函数操作
查看>>
EventCache表太大, 怎么办?
查看>>
Top 10 mistakes in Eclipse Plug-in Development
查看>>
Directx教程(23) 简单的光照模型(2)
查看>>
Java 并发性和多线程
查看>>
IE6下frameset横向滚动条BUG
查看>>
Python线程专题9:线程终止与挂起、实用工具函数
查看>>
用ASP.NET Core 2.1 建立规范的 REST API -- 翻页/排序/过滤等
查看>>
哈默尔的核心竞争力--《可以量化的管理学》
查看>>
Unity中关于作用力方式ForceMode的功能注解
查看>>
view生命周期的一个找父类的控件的方法
查看>>
物理读之LRU(最近最少被使用)的深入解析
查看>>
写给将要毕业的学弟学妹们的感言
查看>>