Linux socket多进程服务器框架三

时间:2022-12-29 07:32:01
在使用select管理服务器连接的时候:
注意1:select是可中断睡眠函数,需要屏蔽信号
注意2:必须获取select的返回值nread,每次处理完一个事件,nread需要-1
注意3:如果客户端的连接超过连接池的大小,需要关闭客户端连接
注意4:获取最大套接字的方法是每次有客户端连接过来时,在和maxfd比较,这样就不用每次select之前都遍历池,查找最大值
服务器
//serhelp.h

#ifndef _vxser
#define _vxser #ifdef __cplusplus
extern "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 __cplusplus
extern "C"
}
#endif
#endif
//serhelp.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#include "commsocket.h" /**
* sersocket_init - socket初始化
* @listenfd:文件描述符
* 成功返回0,失败返回错误码
* */
int sersocket_init(int *listenfd)
{
int ret = ;
if (listenfd == NULL)
{
ret = Sck_ParamErr;
printf("sersocket_init() params not correct !\n");
return ret;
}
//初始化socket环境
int fd = socket(AF_INET, SOCK_STREAM, );
if (fd == -)
{
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 = ;
if (listenfd < || port < || port > )
{
ret = Sck_ParamErr;
printf("listen_socket() params not correct !\n");
return ret;
}
//reuse addr
int optval = ;
ret = setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &optval,
sizeof(optval));
if (ret == -)
{
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 == -)
{
ret = Sck_BaseErr;
perror("bind() err");
return ret;
}
//listen
ret = listen(listenfd, SOMAXCONN);
if (ret == -)
{
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 = ;
//屏蔽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[] = { };
int i = ;
for (i = ; i < ; i++)
{
socketPond[i] = -;
}
//定义池子最后一个元素的下标
int maxindex = ;
//定义文件描述符中值最大的fd
int maxfd = listenfd;
//将监听套接字加入到集合中
FD_SET(listenfd, &allsets);
struct sockaddr_in peeraddr;
socklen_t peerlen = sizeof(struct sockaddr_in);
//定义接收缓冲区
char buf[MAXBUFSIZE] = { };
int buflen = ;
int conn = ;
int nread = ;
while ()
{
readfds = allsets;
do
{
nread = select(maxfd + , &readfds, NULL, NULL, NULL);
} while (nread == - && errno == EINTR);//屏蔽信号(重点)
if (nread == -)
{
perror("select() err");
return;
} else if (nread == )
{
//超时
continue;
} else if (nread > )
{
//执行操作
//1.处理服务器监听套接字
if (FD_ISSET(listenfd, &readfds))
{
//客户端有连接完成三次握手
memset(&peeraddr, , sizeof(struct sockaddr_in));
peerlen = sizeof(struct sockaddr_in);
conn = accept(listenfd, (struct sockaddr *) &peeraddr,
&peerlen);
if (conn == -)
{
perror("accept() err");
break;
}
printf("accept from %s\n", inet_ntoa(peeraddr.sin_addr));
//将客户端套接字加入池子中
for (i = ; i < ; i++)
{
if (socketPond[i] == -)
{
socketPond[i] = conn;
//数组最大下标后移
if (maxindex <= i)
maxindex = i + ;
break;
}
}
//如果超过最大连接数,直接关闭连接(重点)
if (i == )
{
close(conn);
continue;
}
//将客户端套接字加入到监听集合中
FD_SET(conn, &allsets);
//每新加一个连接,就更新最大套接字(重点)
if(conn>maxfd)
maxfd=conn;
//需要处理的事件数-1(重点)
if (--nread <= )
continue;
}
//2.客户端读事件
for (i = ; i < maxindex; i++)
{
if (socketPond[i] == -)
continue;
if (FD_ISSET(socketPond[i], &readfds))
{
//接收客户端信息
memset(buf, , sizeof(buf));
buflen = MAXBUFSIZE;
ret = socket_recv(socketPond[i], buf, &buflen);
if (ret == -)
{
//接收信息出错,关闭套接字
close(socketPond[i]);
//将该套接字移除池子
socketPond[i] = -;
//将该套接字移除监听集合
FD_CLR(conn, &allsets);
} else
{
//打印信息
fputs(buf, stdout);
//向客户端发送数据
ret = socket_send(socketPond[i], buf, buflen);
if (ret == -)
{
//发送数据出错,关闭套接字
close(socketPond[i]);
//将该套接字移除池子
socketPond[i] = -;
//将该套接字移除监听集合
FD_CLR(conn, &allsets);
}
}
//处理的事件数-1
if (--nread <= )
break;
}
}
}
}
return;
}
//服务器
#include "serhelp.h"
#include <stdio.h>
#include "commsocket.h" int main()
{
int ret = ;
int sockfd = ;
//初始化socket
ret = sersocket_init(&sockfd);
if (ret != )
{
printf("error message:%s\n", strsockerr(ret));
return -;
}
//监听
ret = listen_socket(sockfd, );
if (ret != )
{
printf("error message:%s\n", strsockerr(ret));
return -;
}
//运行
run_server(sockfd);
return ;
}

.SUFFIXES:.c .o
CC=gcc
SRCS1=mserver.c\
serhelp.c\
commsocket.c\
sockhelp.c
OBJS1=$(SRCS1:.c=.o)
EXEC1=mser
SRCS2=mclient.c\
clthelp.c\
commsocket.c\
sockhelp.c
OBJS2=$(SRCS2:.c=.o)
EXEC2=mcl start:$(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 $(OBJS2)
rm -f $(EXEC1)
rm -f $(EXEC2)

Linux socket多进程服务器框架三的更多相关文章

  1. Linux socket多进程服务器框架一

    重点:socket共用方法中错误码的定义以及错误码的解析 底层辅助代码 //serhelp.h #ifndef _vxser #define _vxser #ifdef __cplusplus ext ...

  2. Linux socket多进程服务器框架二

    客户端未解决Bug:子进程或者父进程退出的时候,我无法做到两个进程都调用clt_socket_Destory()方式释放socket句柄, 但是进程退出后,相应的资源也会释放,有一定影响,但是不大,以 ...

  3. linux socket高性能服务器处理框架

    这个博客很多东西 http://blog.csdn.net/luozhonghua2014/article/details/37041765   思考一种高性能的服务器处理框架 1.首先需要一个内存池 ...

  4. LINUX环境并发服务器的三种实现模型

    服务器设计技术有很多,按使用的协议来分有TCP服务器和UDP服务器.按处理方式来分有循环服务器和并发服务器. 1  循环服务器与并发服务器模型 在网络程序里面,一般来说都是许多客户对应一个服务器,为了 ...

  5. workerman是一个高性能的PHP socket服务器框架

    workerman-chatorkerman是一款纯PHP开发的开源高性能的PHP socket服务器框架.被广泛的用于手机app.手游服务端.网络游戏服务器.聊天室服务器.硬件通讯服务器.智能家居. ...

  6. PHP socket 服务器框架集

    1.Swoole:重新定义PHP PHP语言的高性能网络通信框架,提供了PHP语言的异步多线程服务器,异步TCP/UDP网络客户端,异步MySQL,数据库连接池,AsyncTask,消息队列,毫秒定时 ...

  7. &lbrack;C&plus;&plus;&rsqb;Linux之多进程运行代码框架

    声明:如需引用或者摘抄本博文源码或者其文章的,请在显著处注明,来源于本博文/作者,以示尊重劳动成果,助力开源精神.也欢迎大家一起探讨,交流,以共同进步- 0.0  多进程代码框架示例 /* @url: ...

  8. Linux socket 类封装 (面向对象方法)

    /* * socketfactory.h * * Created on: 2014-7-19 * Author: root */ #ifndef SOCKETFACTORY_H_ #define SO ...

  9. 【LINUX&sol;UNIX网络编程】之使用消息队列,信号量和命名管道实现的多进程服务器(多人群聊系统)

    RT,使用消息队列,信号量和命名管道实现的多人群聊系统. 本学期Linux.unix网络编程的第三个作业. 先上实验要求: 实验三  多进程服务器 [实验目的] 1.熟练掌握进程的创建与终止方法: 2 ...

随机推荐

  1. MVC项目中使用js 设置Checkbox的选中事件

    要实现的效果是,当点击checkbox时,跳转到Action中 CheckBox实例: View界面: @Html.CheckBox("prd.IsChecked", Model. ...

  2. map 与 unordered&lowbar;map

    两者效率对比: #include <iostream> #include <string> #include <map> #include <unordere ...

  3. 引入第三方库错误Undefined symbols for architecture i386&colon; &lowbar;OBJC&lowbar;CLASS&lowbar;&dollar;的解决方案

    引起标题上所导致的错误是因为你的第三方库没有放入到Compile Sources里面去. 需要到你项目的Targets>>Build Phases>>Compile Sourc ...

  4. CSS3秘笈第三版涵盖HTML5学习笔记13~17章

    第13章,构建基于浮动的布局 使用的是float(浮动)属性 注:float:none值将取消所有浮动,通常只用来取消元素中已经应用的浮动. 切记:不需要给正文的div设计宽度,即使设计成固定宽度也不 ...

  5. &lbrack;PWA&rsqb; 8&period;Unobtrusive update&colon; Delete old cache and only keep one&comma; hard refresh to let new SW to take control

    So once you modify the code, service worker will auto create a new one and it won't take control ove ...

  6. git阶段学习总结

    学习git大约有两个星期了,脑子里总算有点干货了,可以拿出来总结一下: git,用于版本控制的,刚开始觉得它是linux下默认的命令,其实也是个工具需要apt-get install git 安装一下 ...

  7. 利用泛型抽取Dao层,加事务注解问题(java&period;lang&period;Class cannot be cast to java&period;lang&period;reflect&period;ParameterizedType)

    想利用泛型抽取BaseDao层,简化操作时出现故障: @Transactional这个注解是能够继承的.于是就想写在抽取的BaseDao层上,让实现的类能够不用写@Transactional,就可开启 ...

  8. js读取txt文件

    $('#selectAreaFile').on('change',function(e){//用户区域的文件选择        var files=e.target.files;        if ...

  9. 理解 tf&period;Variable、tf&period;get&lowbar;variable以及范围命名方法tf&period;variable&lowbar;scope、tf&period;name&lowbar;scope

    tensorflow提供了通过变量名称来创建或者获取一个变量的机制.通过这个机制,在不同的函数中可以直接通过变量的名字来使用变量,而不需要将变量通过参数的形式到处传递. 1. tf.Variable( ...

  10. base &vert; Tread类

    Tread类 Linux中,每个进程有一个pid,类型pid_t,由getpid()取得.Linux下的POSIX线程也有一个id,类型 pthread_t,由pthread_self()取得,该id ...