网络编程 lesson6 服务器模型和网络超时检测

这篇具有很好参考价值的文章主要介绍了网络编程 lesson6 服务器模型和网络超时检测。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

服务器模型介绍

网络编程服务器模型

循环服务器模型

并发服务器模型

1. 多线程服务器

2. 多进程服务器

3. 事件驱动服务器

网络超时检测

应用场景

设置超时检测的方式

1.利用函数参数设置

代码示例

2.利用socket属性设置

3.利用alarm定时器设置

代码示例


服务器模型介绍

在网络模型中,服务器模型是指在计算机网络中扮演服务器角色的计算机系统或软件。它用于接收和处理客户端的请求,并向客户端提供所需的服务或资源。以下是一些常见的服务器模型:

  1. 客户端/服务器模型:这是最常见的服务器模型之一。在这种模型中,客户端(例如个人计算机、智能手机或其他设备)发送请求到服务器,服务器处理这些请求并返回响应。这种模型适用于诸如网页浏览、电子邮件、文件传输等各种应用。
  2. 分布式服务器模型:在分布式服务器模型中,多台服务器协同工作,共同处理客户端的请求。这种模型可以提高系统的性能和可伸缩性,因为负载可以在多个服务器之间分配,而不是由单个服务器承担所有请求。
  3. 客户端/代理/服务器模型:在这种模型中,代理服务器充当位于客户端和目标服务器之间的中间人。客户端发送请求到代理服务器,代理服务器代表客户端与目标服务器通信,并将响应返回给客户端。这种模型常用于提供缓存、负载均衡和安全性增强等功能。
  4. 对等网络模型:在对等网络模型中,计算机之间没有明确的客户端和服务器角色。相反,所有计算机都可以充当客户端和服务器,并与其他计算机直接通信。这种模型适用于对等文件共享、即时通讯等应用。
  5. 云服务器模型:云服务器模型是指在云计算环境中提供的服务器服务。云服务器提供虚拟化的计算资源,客户可以根据需要动态分配和管理这些资源。这种模型具有弹性和可伸缩性,适用于处理大规模的网络流量和复杂的应用。

这些服务器模型在不同的网络环境和应用场景中有不同的适用性。根据具体的需求和目标,可以选择适当的服务器模型来满足网络服务的要求。

网络编程服务器模型

在网络程序里面,通常都是一个服务器处理多个客户机。

为了处理多个客户的请求,服务器的程序有不同的处理方式。

循环服务器模型

循环服务器模型(Round Robin Server Model)是一种负载均衡的服务器模型。在这种模型中,多台服务器按照轮询的方式依次接收和处理客户端的请求,以实现请求的均衡分配。循环服务器一次只能响应一个客户端的请求。伪代码如下

socket() //创建套接字
bind()//绑定套接字
listen()//监听
while(1)
{
    accept();//创建新套接字和客户端连接
    while(1)
    {
        process();//对接收的数据进行处理
    }
    close();//关闭套接字
}

并发服务器模型

并发服务器模型(Concurrent Server Model)是一种服务器模型,旨在处理同时到达的多个客户端请求。在这种模型中,服务器能够同时处理多个请求,而无需等待前一个请求的完成。

以下是一种常见的并发服务器模型:

1. 多线程服务器

在多线程服务器模型中,服务器为每个客户端请求创建一个独立的线程来处理。当有新的请求到达时,服务器创建一个新的线程,并将该请求分配给该线程进行处理。这样,服务器可以同时处理多个请求,每个请求都在独立的线程中执行。这种模型具有较低的开销和快速的响应时间,但需要额外的线程管理和同步机制来确保线程安全性。伪代码如下

socket();
bind();
listen();
while(1)
{
    accept();
    if(fork()==0)//子进程
    {
        while(1)
        {
            process();//进行处理
        }
        close();
        exit();
    }
    else
    {
        
    }
}
//注:收到客户端消息后,打印下是来自哪个客户端的数据(来电显示)
//注:使用SIGCHLD来处理子进程结束的信号,信号函数中回收进程资源。
//当子进程结束时,会向其父进程发送一个SIGCHLD信号。这个信号通知父进程子进程的状态发生了变化,
//可以通过捕捉SIGCHLD信号来处理子进程的退出状态。

2. 多进程服务器

在多进程服务器模型中,服务器为每个客户端请求创建一个独立的进程来处理。每个进程具有自己的内存空间和执行环境,因此可以独立地执行请求。这种模型提供了更好的隔离性和稳定性,但进程间切换的开销较大。伪代码如下

socket()
bind();
listen();
while(1)
{
	accept();
	pthread_create();//创建线程
}

3. 事件驱动服务器

在事件驱动服务器模型中,服务器使用异步I/O和事件循环机制来处理多个客户端请求。服务器使用单个线程或进程来接收和处理所有的请求,并使用事件通知机制来处理客户端的I/O操作。这种模型具有高效的资源利用率和可扩展性,适用于处理大量并发请求。

借助select、poll、epoll机制,将新连接的客户端描述符增加到描述符表中,只需要一个线程即可处理所有的客户端连接,在嵌入式开发中应用广泛,不过代码写起了稍显繁琐。、

网络超时检测

应用场景

在网络通信中,很多操作会使得进程阻塞:

TCP套接字中的recv/accept

UDP套接字中的recvfrom

超时检测的必要性

避免进程在没有数据时无限制地阻塞

实现某些特定协议要求,比如某些设备规定,发送请求数据后,如果多长时间后没有收到来自设备的回复,需要做出一些特殊处理

设置超时检测的方式

1.利用函数参数设置

select,poll,epoll函数可以通过最后一个参数设置超时检测

//1.select函数设置超时检测
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
struct timeval tm={2,0};//设置2s打算阻塞
sret=select(maxfd+1,&tempfds,NULL,NULL,&tm);
//通过设置第5个参数来进行超时检测
struct timeval{
    long tv_sec;//秒
    long tv_usec;//微秒
}

//2.poll设置超时
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
//第三个参数:时间单位是毫秒 -1阻塞, 2000=2s
 ret = poll(event, num, 2000);//超时检测时间为2s

//3.epoll函数设置超时
int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout);
//第四个参数:时间单位是毫秒 -1阻塞, 2000=2s
ret = epoll_wait(epfd, events, 20, 2000);

上面设置超时后的返回值:
<0	error
=0	超时
>0	正常

代码示例

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>

void *mythread(void *arg)
{
    int acceptfd = *((int *)arg); //4
                                  //循环收发消息
    char buf[128];
    int ret;
    while (1)
    {
        ret = recv(acceptfd, buf, sizeof(buf), 0);
        if (ret < 0)
        {
            perror("recv err.");
            return NULL;
        }
        else if (ret == 0)
        {
            printf("client exit\n");
            close(acceptfd);
            break;
        }
        else
        {
            printf("buf:%s\n", buf);
        }
    }
    pthread_exit(NULL); //return NULL;
}
int main(int argc, char const *argv[])
{
    if (argc != 2)
    {
        printf("please input %s <port>\n", argv[0]);
        return -1;
    }
    //1.创建流式套接字
    int sockfd = socket(AF_INET, SOCK_STREAM, 0); //链接
    if (sockfd < 0)
    {
        perror("socket err.");
        return -1;
    }
    printf("sockfd:%d\n", sockfd); //3
    //填充ipv4的通信结构体

    struct sockaddr_in saddr, caddr;
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(atoi(argv[1])); 
    saddr.sin_addr.s_addr = inet_addr("0.0.0.0");

    socklen_t len = sizeof(caddr);

    //2.绑定套接字 ip和端口(自己)
    if (bind(sockfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
    {
        perror("bind err.");
        return -1;
    }
    printf("bind ok.\n");

    //3.监听
    if (listen(sockfd, 5) < 0)
    {
        perror("listen err.");
        return -1;
    }
    printf("listen ok.\n");

    //4.阻塞等待客户端链接
    while (1)
    {
        int acceptfd = accept(sockfd, (struct sockaddr *)&caddr, &len);
        if (acceptfd < 0)
        {
            perror("accept err.");
            return -1;
        }
        printf("acceptfd=%d\n", acceptfd); //通信
        printf("client:ip=%s port=%d\n",
               inet_ntoa(caddr.sin_addr), ntohs(caddr.sin_port));

        pthread_t tid;
        pthread_create(&tid, NULL, mythread, &acceptfd);
        pthread_detach(tid);
    }
    close(sockfd);
    return 0;
}

2.利用socket属性设置

socket属性表

选项名称        说明                  数据类型 
======================================================================== 
	SOL_SOCKET  应用层
------------------------------------------------------------------------ 
SO_BROADCAST	允许发送广播数据          int 
SO_DEBUG		允许调试            		 int 
SO_DONTROUTE    不查找路由                 int 
SO_ERROR        获得套接字错误             int 
SO_KEEPALIVE    保持连接                  int 
SO_LINGER       延迟关闭连接               struct linger 
SO_OOBINLINE    带外数据放入正常数据流           int 
SO_RCVBUF       接收缓冲区大小               int 
SO_SNDBUF       发送缓冲区大小               int 
SO_RCVLOWAT     接收缓冲区下限               int 
SO_SNDLOWAT     发送缓冲区下限              int 
SO_RCVTIMEO     接收超时                 struct timeval 
SO_SNDTIMEO     发送超时                 struct timeval 
SO_REUSEADDR    允许重用本地地址和端口          int 
SO_TYPE         获得套接字类型              int 
SO_BSDCOMPAT    与BSD系统兼容               int 
==========================================================================             
         IPPROTO_IP  IP层/网络层
----------------------------------------------------------------------------
IP_HDRINCL      在数据包中包含IP首部          int 
IP_OPTINOS      IP首部选项               int 
IP_TOS          服务类型 
IP_TTL          生存时间                int 
IP_ADD_MEMBERSHIP       将指定的IP加入多播组                    struct ip_mreq
==========================================================================            
		IPPRO_TCP  传输层
-----------------------------------------------------------------------------
TCP_MAXSEG      TCP最大数据段的大小            int 
TCP_NODELAY     不使用Nagle算法             int  

API接口文章来源地址https://www.toymoban.com/news/detail-462313.html

int getsockopt(int sockfd,int level,int optname,void *optval,socklen_t *optlen)
int setsockopt(int sockfd,int level,int optname,void *optval,socklen_t optlen)
功能:获得/设置套接字属性
参数:
sockfd:套接字描述符
level: 协议层
		SOL_SOCKET(应用层)
		IPPROTO_TCP(传输层)
		IPPROTO_IP(网络层)
optname:选项名
		SO_BROADCAST    允许发送广播数据            int 
		SO_RCVBUF       接收缓冲区大小              int 
		SO_SNDBUF       发送缓冲区大小              int 
		SO_RCVTIMEO     接收超时                	struct timeval 
		SO_SNDTIMEO     发送超时                	struct timeval
optval:选项值
optlen:选项值大小指针
设置超时检测

struct timeval{
    long tv_sec; //秒
    long tv_usec; //微秒
}
//设置接收超时
struct timeval tm ={2,0};
setsockopt(acceptfd,SOL_SOCKET,SO_RCVTIMEO,&tm,sizeof(tm));
//设置应用层的发送超时


//设置端口和地址重用
int optval=1;
setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&optval,sizeof(optval));
//设置应用层,允许重用端口和地址

3.利用alarm定时器设置

alarm(5) 闹钟	定时器
//5秒之后,会有一个信号产生SIGALRM
int sigaction(int signum,const struct *act,struct sigaction *oldact);
功能:对接收到的指定信号处理
struct sigaction{
	void     (*sa_handler)(int);
};

//设置信号属性
struct sigaction act;
sigaction(SIGALRM,NULL,&act);//获取原属性
act.sa_handler=handler;//修改属性
sigaction(SIGALRM,&act,NULL);//将修改的属性设置回去

注:
在recv前调用alarm函数
alarm的 SIGALRM信号产生后会打断(终端)下面的系统调用recv;
打断后相当于recv执行完毕。

代码示例

#include <stdio.h>
#include <signal.h>
#include <unistd.h>

void handler(int sig)
{
    printf("timeout\n");
}

int main(int argc, char const *argv[])
{
    char buf[32];
    //修改信号的属性
    struct sigaction act;
    sigaction(SIGALRM,NULL,&act);
    act.sa_handler=handler;
    sigaction(SIGALRM,&act,NULL);

    while(1)
    {
        alarm(5);
        printf("hello\n");
        if(fgets(buf,sizeof(buf),stdin) == NULL)
        {
            perror("fgets err.");
            continue;
        }
        printf("buf:%s\n",buf);
    }
    return 0;
}

到了这里,关于网络编程 lesson6 服务器模型和网络超时检测的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java 网络编程 —— 创建多线程服务器

    一个典型的单线程服务器示例如下: 服务端接收到一个客户连接,就与客户进行通信,通信完毕后断开连接,然后接收下一个客户连接,假如同时有多个客户连接请求这些客户就必须排队等候。如果长时间让客户等待,就会使网站失去信誉,从而降低访问量。 一般用并发性

    2024年02月02日
    浏览(47)
  • 网络编程: 服务器百万连接实现

    实验内容: 用三个客户端与服务器建立百万连接 服务器代码: Reactor 将实验遇到的问题记录如下 一个TCP连接叫做TCP控制块(tcp control block)。区分网络连接的五元组元素有 添加功能 增加服务器监听端口 如果服务器只用一个端口,那么至少需要10e6/(2^16-1024) ≈ 16台虚拟机。(能分

    2024年01月20日
    浏览(48)
  • 【skynet】 网络编程之回显服务器

    skynet 提供了一套 tcp 的 API ,本文将给出简单的回显服务器实现,以及讲解。 拉取 skynet 工程 编译 负责启动 gate 服务 \\\"L\\\" 表示客服端的消息前带四字节大端序的 msg_size skynet.address(skynet.self()) 把自己设置为 watchdog ,有新连接通过 text 消息告诉自己 port TCP 监听端口 0 将 TCP 数据

    2024年04月25日
    浏览(36)
  • linux并发服务器 —— linux网络编程(七)

    C/S结构 - 客户机/服务器;采用两层结构,服务器负责数据的管理,客户机负责完成与用户的交互;C/S结构中,服务器 - 后台服务,客户机 - 前台功能; 优点 1. 充分发挥客户端PC处理能力,先在客户端处理再提交服务器,响应速度快; 2. 操作界面好看,满足个性化需求; 3.

    2024年02月09日
    浏览(74)
  • 网络编程六--UDP服务器客户端

    UDP(User Datagram Protocol)称为用户数据报协议,是一种无连接的传输协议。 UDP的主要应用在即使丢失部分数据,也不影响整体效果的场景。例实时传输视频或音频时,即使丢失部分数据,也不会影响整体效果,只是会有轻微的画面抖动或杂音。 UDP服务器/客户端不像TCP那样,交

    2024年02月15日
    浏览(49)
  • 【网络编程】高性能并发服务器源码剖析

      hello !大家好呀! 欢迎大家来到我的网络编程系列之洪水网络攻击,在这篇文章中, 你将会学习到在网络编程中如何搭建一个高性能的并发服务器,并且我会给出源码进行剖析,以及手绘UML图来帮助大家来理解,希望能让大家更能了解网络编程技术!!! 希望这篇文章能

    2024年04月15日
    浏览(55)
  • 云服务器搭建与部署【Unity网络编程(一)】

    1.购买云服务器 新用户第一次买不贵,我在腾讯云买的,学生2G2核CPU20元3个月,36元半年,就买了半年的,只是简单的测试和学习 2.购买后建议选择CentOS系统,之前选择windows server系统,然后在XShell中一直连接不上 在服务器可以看到公网和内网了 3.重置密码 如果不重置的话登

    2023年04月20日
    浏览(42)
  • Linux学习之网络编程3(高并发服务器)

    Linux网络编程我是看视频学的,Linux网络编程,看完这个视频大概网络编程的基础差不多就掌握了。这个系列是我看这个Linux网络编程视频写的笔记总结。 问题: 根据上一个笔记,我们可以写出一个简单的服务端和客户端通信,但是我们发现一个问题——服务器只能连接一个

    2024年02月01日
    浏览(49)
  • 网络编程(8.14)TCP并发服务器模型

    作业: 1. 多线程中的newfd,能否修改成全局,不行,为什么? 2. 多线程中分支线程的newfd能否不另存,直接用指针间接访问主线程中的newfd,不行,为什么? 多线程并发服务器模型原代码: 1.将newfd改成全局变量效果:  答:不行,因为newfd是全局变量的话,客户端连接后生成

    2024年02月13日
    浏览(48)
  • 【网络编程】网络套接字&udp通用服务器和客户端

    端口号(port)是传输层协议的内容: 端口号是一个2字节16位的整数(uint16) 端口号用来标识主机上的一个进程 IP地址+port能够标识网络上的某一台主机和某一个进程 一个端口号只能被一个进程占用 此处我们先对TCP(Transmission Control Protocol 传输控制协议) 有一个直观的认识,后面再

    2024年02月16日
    浏览(213)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包