精华内容
下载资源
问答
  • 单线程服务器模型是最简单的一个服务器模型,几乎我们所有程序员在刚开始接触网络编程(不管是B/S结构还是C/S结构)都是从这个简单的模型开始。这种模型只提供同时一个客户端访问,多个客户端访问必须要等到前一个...

    单线程服务器模型是最简单的一个服务器模型,几乎我们所有程序员在刚开始接触网络编程(不管是B/S结构还是C/S结构)都是从这个简单的模型开始。这种模型只提供同时一个客户端访问,多个客户端访问必须要等到前一个客户端访问结束,一个一个排队,即提供一问一答服务。

    图2-6-1-1 单线程阻塞服务器模型

     

        图2-6-1-1展示了单线程阻塞服务器是怎样响应客户端的访问。首先,服务器必须初始化一个Serversocket实例,绑定某个端口号,并使之监听客户端的访问,以此提供一种服务。接着客户端1远程调用服务器的这个服务,服务器接受到请求后,对其进行处理,并返回信息给客户端1,整个过程都是在一个线程里面完成的。最后,就算客户端2在服务器处理完客户端1之前就进行请求访问,也要等服务器对客户端1响应完后,才会对客户端2进行响应处理。

        我们注意到,大部分的socket操作都是阻塞的,所谓阻塞是指调用后不马上返回调用结果,而让当前线程一直阻塞,只有当该调用获得结果或者超时时才会返回。而我们的图2-6-1-1也有很多个节点都是阻塞的,例如,服务器阻塞监听客户端,直到有客户端访问才返回一个socket;对于客户端,建立一个socket连接后,也进行阻塞,直到服务器响应。几乎所有的IO操作都会产生阻塞,在网络编程中体现在socket的通信。这种阻塞给网络编程带来了一个问题,如图中黑块1和黑块2部分,当服务器处理完进行IO操作(这里的IO操作其实是给客户端发送消息)时,服务器必须要等到客户端成功接收才能继续往下处理另外一个客户端的请求,在此期间,线程将无法执行任何运算跟响应任何客户端请求。而如果这过程永远发送不到客户端,服务器就一直阻塞在那里了,不会接着处理任何事情。

        这种模型的特点是:最简单的服务器模型,整个运行过程都只有一个线程,只能支持同时处理一个客户端的请求,如果多个客户端访问必须排队等待,服务器系统资源消耗较小,但并发能力低,如果遇到IO操作出现错误异常将导致服务器停止运行,容错能力差。一般这种模型一般用在访问跟并发量少,请求是短暂的、无状态的,对响应时间要求不高,处理逻辑较复杂的场合。




    ==========广告时间==========

    公众号的菜单已分为“分布式”、“机器学习”、“深度学习”、“NLP”、“Java深度”、“Java并发核心”、“JDK源码”、“Tomcat内核”等,可能有一款适合你的胃口。


    鄙人的新书《Tomcat内核设计剖析》已经在京东销售了,有需要的朋友可以购买。感谢各位朋友。


    [为什么写《Tomcat内核设计剖析》](http://blog.csdn.net/wangyangzhizhou/article/details/74080321)

    =========================

    展开全文
  • 针对单线程服务器模型的特点,我们可以对其进行改进,使之能对多个客户端同时进行响应。最简单的改进即是使用多线程(或多进程)服务器模型,在应用层级别,我们一般采用多线程模式。多线程能让多个客户端同时请求,...

    针对单线程服务器模型的特点,我们可以对其进行改进,使之能对多个客户端同时进行响应。最简单的改进即是使用多线程(或多进程)服务器模型,在应用层级别,我们一般采用多线程模式。多线程能让多个客户端同时请求,并能几乎同时对这些请求进行响应,而不用排队一个一个处理,能同时为多个客户端提供一问一答的服务。

    图2-6-1-2 多线程阻塞服务器模型

     

    多线程服务器模型核心就是利用多线程机制,为每个客户端分配一个线程。如图2-6-1-2,服务器初始化一个Serversocket实例,绑定某个端口号,并使之监听客户端的访问。两个客户端几乎同时过来请求,服务器在接收到客户端请求后,创建两条线程进行处理,直到响应完成。在这过程中,服务器只是简单的负责接收消息,然后交给处理者线程来处理,服务器能在短时间内接收多个客户端的请求。

    这种模型也是阻塞式的,因为每个线程向客户端写入消息并不是马上返回的,图2-6-1-2中黑块这段时间片就是阻塞时间。但这种模式比单线程处理性能明显高了,不用等到第一个请求处理完才处理第二个。对于多线程,如果线程数大于CPU数量,那么操作系统将会在多个线程之间调度,从而使其他线程能使用CPU,每调度一次导致一次上下文切换,大多通用的处理器中,每次调度大概需要5000-10000个时钟周期,大概几微妙。

    用这种多线程服务器模型就能真正地完美解决问题了吗?其实不然,随着客户端的数量越来越多,当达到成百上千路连接请求时,多线程操作会严重消耗系统cpu资源,并且多线程更容易进入假死状态。对此提出了“线程池”的概念,线程池在启动时先把一定数量的线程先创建好放到内存中,并且使用完不真正销毁线程,而是放回池里,以供新任务使用。这种缓存池机制能有效减少线程创建与销毁的频率,大大降低系统开销。这种机制在Tomcat中也是有所体现,如图2-6-1-3,当一个请求过来时尝试从池里获取一个线程,如果有空闲线程则返回一个线程供使用,而如果没有空闲线程了则直接关闭socket连接拒绝服务,保证服务器在处理能力范围内运行


    图2-6-1-3 多线程阻塞服务器模型-线程池

     

    多线程服务器模型的特点:能支持对多个客户端同时进行响应,处理能力得到大大的提高,有较大的并发量,但服务器系统资源消耗较大,同时拥有较复杂的结构,实现的代码也相对比较复杂。这种模型适用于访问并发量较大,请求是短期的、无状态的,业务逻辑比较复杂,对响应时间要求较高的场合。




    ==========广告时间==========

    公众号的菜单已分为“分布式”、“机器学习”、“深度学习”、“NLP”、“Java深度”、“Java并发核心”、“JDK源码”、“Tomcat内核”等,可能有一款适合你的胃口。


    鄙人的新书《Tomcat内核设计剖析》已经在京东销售了,有需要的朋友可以购买。感谢各位朋友。


    [为什么写《Tomcat内核设计剖析》](http://blog.csdn.net/wangyangzhizhou/article/details/74080321)

    =========================

    展开全文
  • 服务器模型

    千次阅读 2018-09-14 14:19:26
    服务器模型  硬件服务器:主机 集群  硬件厂商: IBM HP 联想 浪潮    软件服务器:编写的服务端应用程序,在硬件服务器运行,一般依托于操作系统,给用户提供一套完整的服务  httpserver-->处理...
    • 服务器模型

        硬件服务器:主机  集群

        硬件厂商:   IBM  HP  联想  浪潮
        

        软件服务器:编写的服务端应用程序,在硬件服务器上运行,一般依托于操作系统,给用户提供一套完整的服务

        httpserver-->处理HTTP请求
        webserver-->网站的后端应用服务器程序
        邮箱服务器-->邮件处理
        ftp文件服务器-->文件的上传下载


        功能:网络连接  逻辑处理   数据交互    数据传输   协议的实现

        结构:c/s 客户端服务器模型
            b/s 浏览器服务器模型

        服务器目标:处理速度更快    并发量更高    安全性更强  

        硬件:更高的配置   更好的集成分布技术,更好的网络优化和网络安全技术

        软件:占用资源更少,运行更稳定,算法更优良,并发性更好,更容易扩展

    基础服务端模型
        循环模型:循环接受客户端请求,处理请求,同一时刻只能处理一个请求,处理完毕后在处理下一个
        优点:实现简单,占用资源少

        缺点:无法同时处理多个客户端任务

        适用情况:处理的任务可以在短时间完成,不需要建立并发,更适合udp使用

        并发模型:能够同时处理多个客户端请求
            IO并发:IO多路复用
                优点:资源消耗少,IO处理速度快
                缺点:不能适用cpu密集型程序

        多进程/多线程并发:为每个客户端创建单独的进程和线程执行请求

            优点:每个客户端可以长期占有服务器运行程序,能够使用多核资源
            可以处理IO或者cpu运算

            缺点:消耗系统资源高

    多进程并发模型:
        使用fork实现多进程并发
        1.创建套接字,绑定,监听
        2.等待接收客户端请求
        3.创建新的进程来处理客户端请求
        4.原来进程继续等待接收新的客户端连接
        5如果客户端退出则关闭子进程

        cookie:
        在父进程忽略子进程状态改变,子进程退出由系统处理
        signal.signal(signal.SIGCHLD,signal.SIG_IGN)

    # fork_server.py
    from socket import *
    import os
    import sys
    import signal
    
    
    # 客户端处理函数
    def client_handler(c):
        print('处理子进程的请求:',c.getpeername())
        try:
            while True:
                data = c.recv(1024)
                if not data:
                    break
                print(data.decode())
                c.send('收到客户端请求'.encode())
        except(KeyboardInterrupt,SystemError):
            sys.exit('客户端退出')
        except Exception as e:
            print(e)
        c.close()
        sys.exit(0)
    
    # 创建套接字
    HOST = ''
    PORT = 8888
    ADDR = (HOST, PORT)
    
    s = socket()
    s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
    s.bind(ADDR)
    s.listen(5)
    
    
    print('进程%d等待客户端的连接' % os.getpid())
    # 在父进程忽略子进程状态改变,子进程退出由系统处理
    signal.signal(signal.SIGCHLD, signal.SIG_IGN)
    
    while True:
        try:
            c, addr = s.accept()
        except KeyboardInterrupt:
            sys.exit('服务器退出')
        except Exception as e:
            print('Error', e)
            continue
        # 为客户端创建新的进程,处理请求
        pid = os.fork()
        # 子进程处理具体请求:
        if pid == 0:
            s.close()
            client_handler(c)
        # 父进程或者创建失败都继续等待下一个客户端连接
        else:
            c.close()
            continue

     

    展开全文
  • 在网络中,通常组织运行多个名字服务器来提供名字与IP地址之间的转换,各种应用程序通过调用解析器库中的函数来与域名服务系统通信。常用的解析函数: struct hostent * gethostbyname(const char * hostname...

    基本数据结构介绍

    Linux系统是通过提供嵌套字(socket)来进行网络编程的。网络程序通过socket和其他几个函数的调用,会返回一个通用的文件描述符,用户可以将这个描述符看成普通的文件的描述符来操作,这就是Linux的设备无关性的好处。用户可以通过向描述符的读写操作实现网络之间的数据交流。

    表示套接口的socket结构体

    struct socket {
    	socket_state		state;            //指明套接口的连接状态
    	short			type;
    	unsigned long		flags;
    
    	struct fasync_struct	*fasync_list;
    	wait_queue_head_t	wait;
    
    	struct file		*file;            //指向sockfs文件系统中的相应文件
    	struct sock		*sk;            //任何协议族都有其特定的套接口特性,该域就指向特定协议族的套接口对象
    	const struct proto_ops	*ops;            //指明可对套接口进行的各种操作
    };

    描述套接口通用地址的数据结构sockaddr结构体

    由于历史的缘故,在bind、connect等系统调用中,特定于协议的套接口地址结构指针都要强制转换成该通用的套接口地址结构指针。结构形式如下:

    struct sockaddr {
    	sa_family_t	sa_family;	/* address family, AF_xxx	*/
    	char		sa_data[14];	/* 14 bytes of protocol address	*/
    };

    描述因特网地址结构的数据结构sockaddr_in(这里局限于IP4)

    struct sockaddr_in {
            sa_family_t		sin_family;	    /* 描述协议族		*/
            __be16		sin_port;	        /* 端口号			*/
            struct in_addr	sin_addr;	    /* 因特网地址		*/
    
            unsigned char		__pad[__SOCK_SIZE__ - sizeof(short int) -
                    sizeof(unsigned short int) - sizeof(struct in_addr)];
    };

     

    基本网络函数介绍

    表头文件

    #include <sys/types.h>
    #include <sys/socket.h>

    socket()函数

    int socket(int domain, int type, int protocol);

    函数说明:socket()用来建立一个新的socket,也就是向系统注册,通知系统建立一通信端口。

    • 参数domain指定协议域,又称为协议族。常用的协议族有:AF_INET、AF_INET6、AF_LOCAL、AF_ROUTE等等。协议族决定了socket的地址类型,在通信中必须采用对应的地址,如AF_INET决定了要用ipv4地址(32位的)与端口号(16位的)的组合、AF_UNIX决定了要用一个绝对路径名作为地址,完整的定义在usr/include/bits/socket.h内;
    • 参数type指定socket类型。常用的socket类型有:SOCK_STREAM(双向连续且可信的数据流,即TCP)、SOCK_DGRAM(不连续不可信赖的数据包连接)、SOCK_PACKET(和网络驱动程序直接通信)、SOCK_SEQPACKET(连续可信赖的数据包连接)等等;
    • 参数protocol指定协议。常用的协议有:IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等,它们分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议。

    返回值:成功则返回socket描述符,失败则返回-1。

    bind()函数

    int bind(int sockfd, struct sockaddr * my_addr, int addrlen);

    函数说明:bind()函数把一个地址族中的特定地址赋给socket。例如对应AF_INET、AF_INET6就是把一个ipv4或ipv6地址和端口号组合赋给socket。

    • 参数sockfd:即socket描述字,它是通过socket()函数创建了,唯一标识一个socket;
    • 参数addr:一个指向sockaddr类型对象的指针,指向要绑定给sockfd的协议地址。这个地址结构根据地址创建socket时的地址协议族的不同而不同;
    • 参数addrlen:对应的是地址的长度。

    返回值:成功则返回0,失败则返回-1。

    对于不同socket的sockaddr,定义了一个通用的数据结构:

    struct sockaddr {
    	sa_family_t	sa_family;	/* address family, AF_xxx	*/
    	char		sa_data[14];	/* 14 bytes of protocol address	*/
    };

    其中,sa_family为调用socket()时的domain参数,即AF_xxxx值;sa_data最多使用14个字符长度。

    sockaddr结构会因使用不同的socket domain而有不同的结构定义,例如AF_INET:

    struct sockaddr_in {
            sa_family_t    sin_family; /* address family: AF_INET */
            in_port_t      sin_port;   /* port in network byte order */
            struct in_addr sin_addr;   /* internet address */
    };
    
    struct in_addr {
            uint32_t       s_addr;     /* address in network byte order */
    };

    例如AF_INET6:

    struct sockaddr_in6 { 
            sa_family_t     sin6_family;   /* AF_INET6 */ 
            in_port_t       sin6_port;     /* port number */ 
            uint32_t        sin6_flowinfo; /* IPv6 flow information */ 
            struct in6_addr sin6_addr;     /* IPv6 address */ 
            uint32_t        sin6_scope_id; /* Scope ID (new in 2.4) */ 
    };
    
    struct in6_addr { 
            unsigned char   s6_addr[16];   /* IPv6 address */ 
    };

    listen()函数

    int listen(int sockfd, int backlog)

    函数说明:sockfd参数为要监听的socket描述字,backlog参数为相应socket可以排队的最大连接个数。socket()函数创建的socket默认是一个主动类型的,listen()函数将socket变为被动类型的,等待客户的连接请求。

    返回值:成功则返回0,失败则返回-1。

    注意:listen()只适合SOCK_STREAM或SOCK_SEQPACKET的socket类型。如果socket为AF_INET,则参数backlog的最大值为128。backlog不能限制连接的个数,只能限制后备连接(连接请求队列)的大小;一旦调用accept()函数处于请求队列里面的后备连接的数量就减一。

    connect()函数

    int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

    函数说明:sockfd参数为客户端的socket描述字,addr参数为服务器的socket地址,addrlen参数为socket地址的长度。客户端通过调用connect()函数来建立与TCP服务器的连接。

    返回值:成功则返回0,失败返回-1,错误原因存于errno中。

    accept()函数

    int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

    函数说明:sockfd参数为服务器的socket描述字,addr参数为指向struct sockaddr *的指针,用于返回客户端的协议地址,第三个参数为协议地址的长度。

    返回值:如果accpet()成功,那么其返回值是由内核自动生成的一个全新的描述字,代表与返回客户的TCP连接。

    注意:accept()的第一个参数为服务器的socket描述字,是服务器开始调用socket()函数生成的,称为监听socket描述字;而accept()函数返回的是已连接的socket描述字。一个服务器通常仅仅只创建一个监听socket描述字,它在该服务器的生命周期内一直存在。内核为每个由服务器进程接受的客户连接创建了一个已连接socket描述字,当服务器完成了对某个客户的服务,相应的已连接socket描述字就被关闭。

     

    服务器与客户端的信息函数

    字节转换函数

    区分一下网络字节序与主机字节序:

    主机字节序就是我们平常说的大端和小端模式:不同的CPU有不同的字节序类型,这些字节序是指整数在内存中保存的顺序,这个叫做主机序。引用标准的Big-Endian和Little-Endian的定义如下:

    • Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端;
    • Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。

    网络字节序:4个字节的32bit值以下面的次序传输:首先是0~7bit,其次8~15bit,然后16~23bit,最后是24~31bit。这种传输次序称作大端字节序。由于TCP/IP首部中所有的二进制整数在网络中传输时都要求以这种次序,因此它又称作网络字节序。字节序,顾名思义字节的顺序,就是大于一个字节类型的数据在内存中的存放顺序,一个字节的数据没有顺序的问题了。

    所以:在将一个地址绑定到socket的时候,请先将主机字节序转换成为网络字节序,而不要假定主机字节序跟网络字节序一样使用的是Big-Endian。

    为了统一,在Linux下有专门的字节转换函数:

    #include <netinet/in.h>
    
    unsigned long int htonl(unsigned long int hostlong);        //将32位主机字节序转换成网络字节序
    unsigned short int htons(unsigned short int hostshort);        //将16位主机字节序转换成网络字节序
    unsigned long int ntohl(unsigned long int netlong);        //将32位网络字节序转换成主机字节序
    unsigned short int ntohs(unsigned short int netshort);        //将16位网络字节序转换成主机字节序

    在这四个转换函数中,h代表host,n代表network,l代表long,s代表short。

    IP和域名的转换

    在网络上,标志一台计算机可以用名字形式的网址,例如blog.csdn.net/qq_38410730,也可以使用地址的IP形式47.95.164.112,它是一个32位的整数,每个网络节点有一个IP地址,它唯一地确定一台主机,但一台主机可以有多个IP地址。

    在网络中,通常组织运行多个名字服务器来提供名字与IP地址之间的转换,各种应用程序通过调用解析器库中的函数来与域名服务系统通信。常用的解析函数有:

    struct hostent * gethostbyname(const char * hostname);            //名字地址转换为数字地址
    struct hostent * gethostbyaddr(const char * addr, int len, int type);            //数字地址转换为名字地址

    函数说明:第二个函数sddr参数为含有IP地址信息的in_addr结构的指针(为了同时传递IPv4之外的其他信息,设置为char*类型的);len参数为地址信息的字节数,IPv4为4,IPv6为16;type参数为地址族信息,IPv4为AF_INET,IPv6为AF_INET6。

    返回值:两个函数失败时返回NULL且设置h_errno错误变量,调用h_strerrno()可以得到详细的错误信息。

    其中,struct hostent的定义为:

    struct hostent
    {
            char *h_name;         //正式主机名
            char **h_aliases;     //主机别名
            int h_addrtype;       //主机IP地址类型:IPV4-AF_INET
            int h_length;		  //主机IP地址字节长度,对于IPv4是四字节,即32位
            char **h_addr_list;	  //主机的IP地址列表
    };
    	
    #define h_addr h_addr_list[0]   //保存的是IP地址
    

    例如:

    #include <stdio.h>
    #include <netdb.h>
    #include <sys/socket.h>
    #include <arpa/inet.h>
     
    int main(int argc, char *argv[])
    {
    	char *ptr, **pptr;
    	struct hostent *hptr;
    	char str[32] = {0};
    	ptr = argv[1];
    	
    	if((hptr = gethostbyname(ptr)) == NULL){
    		printf("gethostbyname error: %s\n", ptr);
    		return 0;
    	}
    	
    	printf("official hostname:%s\n", hptr->h_name);   //主机规范名
    	for(pptr = hptr->h_aliases; *pptr != NULL; pptr++)   //将主机别名打印出来
    		printf("alias: %s\n", *pptr);
    	
    	switch(hptr->h_addrtype)  //根据地址类型,将地址打印出来
    	{
    		case AF_INET:
    		case AF_INET6:
    			pptr = hptr->h_addr_list;
    		
    			for(; *pptr != NULL; pptr++)   //将得到的所有地址打印出来
    			{
    				printf("address: %s\n", inet_ntop(hptr->h_addrtype, *pptr, str, sizeof(str)));   //inet_ntop: 将网络字节序的二进制转换为文本字符串的格式
    				printf("first address: %s\n", inet_ntop(hptr->h_addrtype, hptr->h_addr, str, sizeof(str)));
    			}
    			break;
    		default:
    			printf("unkown address type\n");
    			break;
    	}
    	
    	return 0;
    }

    字符串的IP和32位的IP转换

    网络上用的IP地址都是数字加点构成的,而在struct in_addr结构中用的是32位的IP,把数字加点类型转换成32位IP,可以使用下面两个函数:

    int inet_aton(const char * cp, struct in_addr * inp);        //将数字加点类型转化成32位的IP,存储在inp指针里
    char * inet_ntoa(struct in_addr in);        //将32位的IP转换成数字加点类型

    函数中的a表示ASCII,n代表network。

    注意与下面两个函数的区别:

    in_addr_t inet_addr(const char *cp);        //将数字加点类型转化成32位的IP
    in_addr_t inet_network(const char *cp);        //将数字加点类型转化成32位的IP

    这两个函数与inet_aton()的区别在于:

    这两个函数,当IP是255.255.255.255时,会认为这是个无效的IP地址,这是历史遗留问题,其实在目前大部分的路由器上,这个255.255.255.255的IP都是有效的。而inet_aton()函数认为255.255.255.255是有效的,它不会冤枉这个看似特殊的IP地址。

    服务信息函数

    在网络程序中,用户有时需要知道端口IP和服务信息,这个时候可以使用以下几个函数:

    int getsockname(int sockfd, struct sockaddr *localaddr, int *addrlen);
    int getpeername(int sockfd, struct sockaddr *peeraddr, int *addrlen);
    
    struct servent *getservbyname(const char *servname, const char *protoname);            //某一个协议下的某个服务
    struct servent *getservbyport(int port, const char *protoname);
    
    struct servent
    {
            char *s_name;            //正式服务名
            char **s_aliases;            //别名列表
            int s_port;            //端口号
            char *s_proto;            //使用的协议
    }

    例子:

    struct servent *sptr;
    
    sptr = getservbyname("domain", "udp");        // DNS using UDP
    sptr = getservbyname("ftp", "tcp");        //FTP using TCP
    
    sptr = getservbyport(htons(53), "udp");        // DNS using UDP
    sptr = getservbyport(htons(21), "tcp");        //FTP using TCP
    
    

    参考文章:网络编程学习笔记(getservbyname和getservbyport函数)

     

    完整的读写函数

    一旦用户建立了连接,下一步就是进行通信了。在Linux下,把用户前面建立的通道看作文件描述符,这样服务器端和客户端进行通信时,只要往文件描述符里面读写东西就可以了,就像用户往文件读写一样。

    #include <unistd.h>
    
    ssize_t write(int fd, const void *buf, size_t count);
    ssize_t read(int fd, void *buf, size_t count);

    函数说明:将数据写入已打开的文件内,write()会把参数buf所指的内存写入count个字节到参数fd所指向的文件内。如果顺利,write()会返回实际写入的字节数,当有错误发生时,则返回-1;

    从已打开的文件读取数据,read()会把参数fd所指向的文件传送count个字节到buf指针所指的内存中。返回值为实际读取到的字节数。

    例子:

    //客户端向服务器端写
    struct my_struct my_struct_client;
    write(fd, (void *)&my_struct_client, sizeof(struct my_struct));
    
    //服务器端的读
    char buffer[sizeof(struct my_struct)];
    struct *my_struct_server;
    read(fd, (void *)buffer, sizeof(struct my_struct));
    my_struct_server=(struct my_struct *)buffer;

    需要注意的是:在网络上传递数据时,用户一般都是把数据转化为char类型的数据来传递。接收时也是一样。同时,用户没有必要在网络上传递指针(因为传递指针时没有任何意义的,用户必须传递指针所指向的内容)。

    这里还要注意一下堵塞的问题:

    在阻塞模式下, 对于TCP套接字(默认情况下),当使用 write() 发送数据时:

    • 首先会检查缓冲区,如果缓冲区的可用空间长度小于要发送的数据,那么 write() 会被阻塞(暂停执行),直到缓冲区中的数据被发送到目标机器,腾出足够的空间,才唤醒 write() 函数继续写入数据;
    • 如果TCP协议正在向网络发送数据,那么输出缓冲区会被锁定,不允许写入,write() 也会被阻塞,直到数据发送完毕缓冲区解锁,write() 才会被唤醒;
    • 如果要写入的数据大于缓冲区的最大长度,那么将分批写入;
    • 直到所有数据被写入缓冲区 write() 才能返回。

    当使用 read() 读取数据时:

    • 首先会检查缓冲区,如果缓冲区中有数据,那么就读取,否则函数会被阻塞,直到网络上有数据到来;
    • 如果要读取的数据长度小于缓冲区中的数据长度,那么就不能一次性将缓冲区中的所有数据读出,剩余数据将不断积压,直到有 read() 函数再次读取;
    • 直到读取到数据后 read() 函数才会返回,否则就一直被阻塞。

    这就是TCP套接字的阻塞模式。所谓阻塞,就是上一步动作没有完成,下一步动作将暂停,直到上一步动作完成后才能继续,以保持同步性。

     

    用户数据报发送

    之前的主要是基于TCP协议的网络程序,下面就主要介绍一下基于UDP协议的网络程序。

    表头文件

    #include <sys/types.h>
    #include <sys/socket.h>

    recvfrom()函数

    int recvfrom(int s, void *buf, int len, unsigned int flags, struct sockaddr *from, int *fromlen);

    函数说明:经socket接收数据,recvfrom()用来接收远程主机指定的socket传来的数据,并把数据存到参数buf指向的内存空间,参数len为可接收数据的最大长度。参数flags一般设为0,参数from用来指定欲传送的网络地址,参数fromlen为sockaddr的结构长度。

    返回值:成功则返回接收到的字符数,失败则返回-1。

    sendto()函数

    int sendto(int s, const void *msg, int len, unsigned int flags, const struct sockaddr *to, int tolen);

    函数说明:经socket发送数据,sendto()用来将数据由指定的socket传给对方主机。参数s为已建好连线的socket,如果利用UDP协议则不需经过连线操作。参数msg指向欲连接线的数据内容,参数flags一般设为0,参数to用来指定欲传送的网络地址,参数tolen为sockaddr的结构长度。

    返回值:成功则返回接收到的字符数,失败则返回-1。

     

    下一篇文章:【Linux】Linux网络编程(含常见服务器模型,下篇)

     

    展开全文
  • 当前业界常见服务器性能指标:  TPC-C  TPC-E  TPC-H  SPECjbb2005  SPECjEnterprise2010  SPECint2006 及 SPECint_rate_2006  SPECfp2006 及 SPECfp_rate_2006  SAP SD 2-Tier  LINPACK  
  • 服务器模型——C/S模型和P2P模型

    千次阅读 2017-09-03 21:26:08
    呦呦切克闹,煎饼果子来一套本篇学习两种服务器模型~~ TCP/IP协议在设计和实现上并没有客户端和服务器的概念,在通信过程中所有机器都是对等的。但由于资源都被数据提供者所垄断,所以几乎所有的网络应用程序都...
  • Linux 网络编程——并发服务器的三种实现模型

    万次阅读 多人点赞 2015-05-12 17:40:08
    服务器设计技术很多,按使用的协议来分 TCP 服务器和 UDP ...目前最常用的服务器模型有:·循环服务器服务器在同一时刻只能响应一个客户端的请求·并发服务器服务器在同一时刻可以响应多个客户端的请求UDP ...
  • 一致性模型有哪些

    千次阅读 2021-04-12 00:09:31
    在工程中常用的一致性模型有:强一致性(Strong Consistency), 弱一致性(Weak Consistency),最终一致性(Eventual Consistency 1. 强一致性:系统中的某个数据被成功更新后,后续任何对该数据的读取操作都将得到更新...
  • web服务器运行机制

    千次阅读 2018-05-08 16:09:12
    web服务器运行机制: 1。浏览器发送请求数据到服务器 2。服务器解析请求参数 3。服务器处理用户请求 4。服务器生成响应数据 5。服务器向浏览器送回响应数据   客户端每次请求服务器需要完成如下步骤: ....
  • Tomcat 7服务器线程模型

    千次阅读 2015-08-20 16:48:03
    Tomcat 7服务器网络处理主要由NioEndpoint,其处理客户端连接的主要流程如图所示 图中Acceptor及Worker分别是以线程池形式存在,Poller是一个单线程。注意,与BIO的实现一样,缺省状态下,在server.xml中没有配置...
  • 服务器训练模型的时候,经常因为本地断网而导致模型训练终止。而sreen可以解决这个痛楚。screen是Linux系统下的远程会话工具,也就是可以离线会话。 先安装screen,需要root权限: sudo apt-get install screen...
  • # 1、Write the graph defination to disk writer = tf.summary.FileWriter('graphs/', ...tensorboard --logdir graphs [--port 8888 --host 192.168.1.144] # 括号为可选参数,当在服务器上使用时可能会需要这些参数
  • 5种常见的并发模型

    千次阅读 2020-02-11 21:11:19
    5种常见的并发模型 前言 并发在现在已经是十分常见的问题了,由于人类信息量的增加,很多信息都需要并发处理,原有的串行处理已经很难满足现实的需求。 今天我们来讲一讲5种常见的并发模型 1、Future模型 Future模型...
  • GPU云服务器体验-深度学习模型训练

    千次阅读 2019-08-31 11:20:06
    极客云,为深度学习而生,您只需简单几步操作即可测试和训练您的模型。 1.上传代码和训练集数据(不收费) 上传的数据将会被挂载到 连接后服务器的 /data 目录下 2.选择适合配置,创建云服务器。 我第一次...
  • C++ linux epoll并发服务器模型初探

    千次阅读 2015-08-08 18:37:33
    socket通讯流程图 最简单的可以通讯的C++服务器端代码:#include #include #include #include #include #include <netinet/in.h>#define SERV_PORT 8000int main(voi
  • 利用远程云服务器跑深度学习模型

    千次阅读 2020-03-16 18:06:47
    利用远程云服务器跑深度学习模型主要三个问题需要解决。 一是深度学习环境的搭建,二是已搭建环境的保存,三是远程数据的传输。 深度学习环境的搭建 以阿里云为例,在购买服务器创建实例时,可以在镜像市场选择...
  • web 服务器有哪些

    万次阅读 多人点赞 2018-08-27 16:53:49
    什么是web服务器 "网络服务"(Web Service)的本质,就是通过网络调用其他网站的资源。 Web Service架构和云 如果一个软件的主要部分采用了"网络服务",即它把存储或计算环节"外包"...
  • 概述对于使用 .NET 平台的 Web 应用程序开发,Crystal Decisions 为开发者提供了三种愈加高级的报表对象模型:1....2. 新增的报表应用服务器 (RAS) 对象模型:捆绑在水晶报表 9 开发者版及高级版中
  • 使用windows在Ubuntu服务器运行代码

    千次阅读 2018-11-13 22:40:18
    使用windows在Ubuntu服务器运行代码整体流程安装必备软件连接目标服务器上传自己的代码控制服务器跑代码并得到结果END 整体流程 要到目标服务器的: a) IP地址 b) 用户名 c) 密码 安装必备软件(Xshell 、...
  • 每来一个连接,服务器就会新建一个线程来处理该连接的读写事件。 特点: 1)采用阻塞式 I/O 模型读取数据; 2)每个连接都需要独立的线程完成数据读取,业务处理,数据返回的完整操作。 存在问题: 1)当并发数较大...
  • 相信很多站长们也是不太了解,没关系,今天咱们一起来科普一下,windows和linux哪种服务器好,各自的优劣势有哪些?  最早,投身到Linux阵营当中的是一些想完全掌握自己的命运、想通过自身努力优化这个世界的...
  • 将情感倾向性分析模型部署至华为云服务器一、前言二、云服务器基本介绍三、购买云服务器1.登陆控制台2.配置计费模式3.选择镜像4.创建磁盘5.配置网络6.选择登录方式7.确认配置并购买8.查看购买成功的云服务器四、登陆...
  • I/O模型的选择 通过上一节对各种模型的测试分析,对于如何挑选最适合自己应用程序的I/O模型,大家可能还有些问题。
  • 租用GPU服务器跑深度学习模型心得

    千次阅读 多人点赞 2021-01-05 15:34:16
    相信很多刚接触人工智能学习的人会遇到这个问题,当时用笔记本的CPU在跑一个Unet,19个epoch要跑半个小时...笔记本跑大模型可能也会烧坏显卡。目前实验室还没有多余的显卡让我使用,所以就决定考虑租用GPU服务器
  • 多线程服务器的常用编程模型

    万次阅读 多人点赞 2010-02-12 17:07:00
    多线程服务器的常用编程模型 陈硕 (giantchen_AT_gmail)Blog.csdn.net/Solstice2009 Feb 12 建议阅读本文 PDF 版下载: http://files.cppblog.com/Solstice/multithreaded_server.pdf 本文主要讲我个人在多...
  • 将tensorflow模型部署到服务器

    千次阅读 2019-08-17 19:09:09
    基本思路:利用tensorflow官方提供的tensorflow serving进行部署,同时,为了免去环境配置等麻烦操作,可借助docker容器。 一、服务器环境选择 ...了解的原因大概是:docker需要在linux的环境下运行。但通...
  • 本文为系列博客tensorflow模型部署系列的一部分,用于实现通用模型的独立简单服务器部署。本文主要实现用flask搭建tensorflow模型推理服务器。实现了tensorflow模型服务器端计算方案,并提供相关示例源代码。相关...
  • 点击进入_更多_Java千百问1、jvm常见配置都有哪些了解jvm内存模型看这里:java内存模型是什么样的 了解jvm内存管理看这里:jvm是如何管理内存的 了解jvm垃圾回收机制看这里:java垃圾回收机制是什么jvm配置非常多...
  • 1.常用服务器模型a.迭代服务器只有一个进程/线程处理请求设计方法:一般为单进程,加上select多路复用,非阻塞socketb.迭代/并发混合型服务器平时迭代处理,对消耗大的请求并发处理设计方法:平时是迭代型的服务器处理...
  • 浅谈服务器的C/S模型

    千次阅读 2015-01-29 10:45:15
    过去的一年,做了几个基于C/S模型的客户端和服务器,C/S模型就是“客户端/服务器模型的简写。基于分享就是最好的学习,所以对其进行回顾是很必要的。  其实,TCP/IP协议在设计和实现上并没有客户端和服务器...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 430,553
精华内容 172,221
关键字:

常见的服务器运行模型有哪些