TCP网络服务器模型

本文介绍了两种常见的TCP服务器模型:循环服务器和并发服务器。循环服务器适用于客户端连接时间较短的情况;并发服务器包括多进程、多线程及IO多路复用等实现方式,适合客户端数量较多且连接时间较长的应用场景。
摘要由CSDN通过智能技术生成

服务器模型

1、循环服务器
实现流程:
1)、服务器端从连接请求队列中提取请求,建立连接并返回已连接的套接字。
2)、服务器端通过以连接的套接字循环接收数据,处理并发给客户端,直到客户端关闭连接。
3)、服务器端关闭已连接的套接字,返回步骤 1)。


特点:
    1.服务器采用循环嵌套实现,外层循环一次提取每个客户端的链接请求,建立TCP链接。内层循环接收连接并处理当前客户端的所有数据,知道客户端关闭连接。
      如果当前客户端没有处理结束,其他客户端必须一直等待。
    2.采用这种循环服务器端无法实现对多个客户端服务。适应于客户端连接时间短的情况。 
    3.同一时刻只能处理一个客户端的请求,一般很少使用


服务器代码:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>

int main ()
{
   
//定义结构体变量,作为bind函数的参数
    struct sockaddr_in servAddr ;
   
memset (& servAddr , 0 , sizeof ( servAddr ));
   
servAddr . sin_family = PF_INET ;
   
servAddr . sin_port = htons ( 8888 );
   
servAddr . sin_addr . s_addr = inet_addr ( "127.0.0.1" );

   
//创建套接字
    //返回值为新创建的socket的文件描述符,失败-1
    int servFd = socket ( PF_INET , SOCK_STREAM , 0 );
   
if ( servFd < 0 )
   
{
       
perror ( "socket error!" );
       
return - 1 ;
   
}
   
printf ( "socket ok!\n" );
   
//绑定地址信息
    int ret = bind ( servFd , ( struct sockaddr *)& servAddr , sizeof ( servAddr ));
   
if ( ret < 0 )
   
{
       
perror ( "bind error!" );
       
close ( servFd );
       
return - 1 ;
   
}
   
printf ( "bind ok!\n" );
   
//创建监听队列
    ret = listen ( servFd , 10 );
   
if ( ret < 0 )
   
{
       
perror ( "listen error!" );
       
close ( servFd );
       
return - 1 ;
   
}
   
printf ( "listening.....\n" );

   
while ( 1 )
   
{
       
//接收连接请求
        int connFd = accept ( servFd , NULL , NULL );
       
if ( connFd < 0 )
       
{
           
perror ( "accept error!" );
           
close ( servFd );
           
return - 1 ;
       
}
       
printf ( "accept ok!\n" );

       
char buf [ 1024 ] = { 0 };
       
//接收消息
        ret = recv ( connFd , buf , sizeof ( buf ), 0 );
       
if ( ret < 0 )
       
{
           
perror ( "recv error!" );
           
close ( servFd );
           
close ( connFd );
           
return - 1 ;
       
}
       
printf ( "recv from client: %s\n" , buf );

       
strcat ( buf , "+++" );
       
send ( connFd , buf , sizeof ( buf ), 0 );
       
//关闭套接字
        close ( connFd );
       
sleep ( 10 );
   
}
   
close ( servFd );
   
return 0 ;
}









































































































客户端代码:
#include<stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>


int main ()
{
   
//定义结构体变量,该变量保存的服务器的地址信息,作为connect的参数
    struct sockaddr_in servAddr ;
   
memset (& servAddr , 0 , sizeof ( servAddr ));
   
servAddr . sin_family = PF_INET ;
   
servAddr . sin_port = htons ( 8888 );
   
servAddr . sin_addr . s_addr = inet_addr ( "127.0.0.1" );

   
//创建套接字
    int cliFd = socket ( PF_INET , SOCK_STREAM , 0 );
   
if ( cliFd < 0 )
   
{
       
perror ( "socket error!" );
       
return - 1 ;
   
}
   
printf ( "socket ok!\n" );
   
//发起连接请求
    int ret = connect ( cliFd , ( struct sockaddr *)& servAddr , sizeof ( servAddr ));
   
if ( ret < 0 )
   
{
       
perror ( "connect error!" );
       
close ( cliFd );
       
return - 1 ;
   
}
   
printf ( "connect ok!\n" );
   
char buf [ 1024 ] = "hello world" ;
   
//发送消息
    ret = send ( cliFd , buf , sizeof ( buf ), 0 );
   
if ( ret < 0 )
   
{
       
perror ( "send error!" );


        close(cliFd);
        return -1;
    }
    printf("send ok!\n");

    memset(buf, 0, sizeof(buf));
    recv(cliFd, buf, sizeof(buf), 0);
    printf("recv from server %s\n", buf);
    //关闭套接字
    close(cliFd);
    return 0;

}


















































   





















2 、并发服务器

>>>多进程的并发服务器
   >>>多线程的并发服务器
   >>>IO多路复用的并发服务器
  
  
>>>多进程的并发服务器

   只要有客户端连接服务器,服务器就创建子进程与客户端通信

   创建子进程后,父进程----继续等待其他客户端的连接
               子进程----与客户端通信
                
   总结:多进程服务器,比较浪费资源,适合于客户端数量较少,但是长连接的情况


服务器代码:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <signal.h>

void sigFunc ( int sigNo )
{
   
if ( sigNo == SIGCHLD )
   
{
       
wait ( NULL );
   
}
}

int main ()
{
   
//定义结构体变量,作为bind函数的参数
    struct sockaddr_in servAddr ;
   
memset (& servAddr , 0 , sizeof ( servAddr ));
   
servAddr . sin_family = PF_INET ;
   
servAddr . sin_port = htons ( 8888 );
   
servAddr . sin_addr . s_addr = inet_addr ( "127.0.0.1" );

   
//创建套接字
    //返回值为新创建的socket的文件描述符,失败-1
    int servFd = socket ( PF_INET , SOCK_STREAM , 0 );
   
if ( servFd < 0 )
   
{
       
perror ( "socket error!" );
       
return - 1 ;
   
}
   
printf ( "socket ok!\n" );
   
//绑定地址信息
    int ret = bind ( servFd , ( struct sockaddr *)& servAddr , sizeof ( servAddr ));
   
if ( ret < 0 )
   
{
       
perror ( "bind error!" );
       
close ( servFd );
       
return - 1 ;
   
}
   
printf ( "bind ok!\n" );
   
//创建监听队列
    ret = listen ( servFd , 10 );
   
if ( ret < 0 )
   
{
       
perror ( "listen error!" );
       
close ( servFd );
       
return - 1 ;
   
}
   
printf ( "listening.....\n" );

   
while ( 1 )
   
{
       
//接收连接请求
        int connFd = accept ( servFd , NULL , NULL );
       
if ( connFd < 0 )
       
{
           
perror ( "accept error!" );
           
close ( servFd );
           
return - 1 ;
       
}
       
printf ( "accept ok!\n" );

       
//创建子进程
        pid_t pid ;
       
while (( pid = fork ()) < 0 );
       
if ( 0 == pid )
       
{
           
close ( servFd );
           
char buf [ 1024 ] = { 0 };
           
while ( 1 )
           
{
               
//接收消息
                memset ( buf , 0 , sizeof ( buf ));
               
ret = recv ( connFd , buf , sizeof ( buf ), 0 );
               
if ( ret < 0 )
               
{
                   
perror ( "recv error!" );
                   
close ( connFd );
                   
return - 1 ;
               
}
               
else if ( 0 == ret )
               
{
                   
printf ( "client shutdown!\n" );
                   
break ;
               
}
               
printf ( "recv from client: %s\n" , buf );
               
memset ( buf , 0 , sizeof ( buf ));
               
printf ( "server:" );
               
gets ( buf );
               
send ( connFd , buf , sizeof ( buf ), 0 );
           
}
           
//关闭套接字
            close ( connFd );
           
exit ( 0 );
       
}
       
else
       
{
           
close ( connFd );
           
signal ( SIGCHLD , sigFunc );
       
}

   
}
   
close ( servFd );
   
return 0 ;
}




















































































































































客户端代码:

#include<stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>


int main ()
{
   
//定义结构体变量,该变量保存的服务器的地址信息,作为connect的参数
    struct sockaddr_in servAddr ;
   
memset (& servAddr , 0 , sizeof ( servAddr ));
   
servAddr . sin_family = PF_INET ;
   
servAddr . sin_port = htons ( 8888 );
   
servAddr . sin_addr . s_addr = inet_addr ( "127.0.0.1" );

   
//创建套接字
    int cliFd = socket ( PF_INET , SOCK_STREAM , 0 );
   
if ( cliFd < 0 )
   
{
       
perror ( "socket error!" );
       
return - 1 ;
   
}
   
printf ( "socket ok!\n" );
   
//发起连接请求
    int ret = connect ( cliFd , ( struct sockaddr *)& servAddr , sizeof ( servAddr ));
   
if ( ret < 0 )
   
{
       
perror ( "connect error!" );
       
close ( cliFd );
       
return - 1 ;
   
}
   
printf ( "connect ok!\n" );
   
char buf [ 1024 ];
   
while ( 1 )
   
{
       
memset ( buf , 0 , sizeof ( buf ));
       
printf ( "client:" );
       
gets ( buf );
       
if ( 0 == strcmp ( buf , "quit" ))
       
{
           
break ;
       
}
       
//发送消息
        ret = send ( cliFd , buf , sizeof ( buf ), 0 );
       
if ( ret < 0 )
       
{
           
perror ( "send error!" );
           
close ( cliFd );
           
return - 1 ;
       
}
       
printf ( "send ok!\n" );

       
memset ( buf , 0 , sizeof ( buf ));
       
recv ( cliFd , buf , sizeof ( buf ), 0 );
       
printf ( "recv from server %s\n" , buf );
   
}
   
//关闭套接字
    close ( cliFd );
   
return 0 ;
}



























































   
























>>>多线程的并发服务器
    只要有客户端连接服务器,服务器就创建子线程与客户端通信
    由于在创建子线程时,以及销毁子线程时,比较浪费时间,一般可以使用线程池
    多线程存在的问题:存在资源竞争以及同步的问题
    总结:适合于客户端数量较少,但是长连接的情况

服务器代码:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <pthread.h>


void * threadFunc ( void * arg )
{
   
int connFd = *(( int *) arg );
   
char buf [ 1024 ] = { 0 };
   
while ( 1 )
   
{
       
memset ( buf , 0 , sizeof ( buf ));
       
//接收消息
        int ret = recv ( connFd , buf , sizeof ( buf ), 0 );
       
if ( ret < 0 )
       
{
           
perror ( "recv error!" );
           
close ( connFd );
           
pthread_exit (( void *)- 1 );
       
}
       
else if ( 0 == ret )
       
{
           
printf ( "client shutdown!\n" );
           
break ;
       
}
       
printf ( "recv from client: %s\n" , buf );

       
memset ( buf , 0 , sizeof ( buf ));
        printf("server:");
        gets(buf);
        send(connFd, buf, sizeof(buf), 0);
    }
    close(connFd);
    pthread_exit(NULL);
}

int main()
{
    //定义结构体变量,作为bind函数的参数
    struct sockaddr_in servAddr;
    memset(&servAddr, 0, sizeof(servAddr));
    servAddr.sin_family = PF_INET;
    servAddr.sin_port = htons(8888);
    servAddr.sin_addr.s_addr = inet_addr("127.0.0.1");

    //创建套接字
    //返回值为新创建的socket的文件描述符,失败-1
    int servFd = socket(PF_INET, SOCK_STREAM, 0);
    if(servFd < 0)
    {
        perror("socket error!");
        return -1;
    }
    printf("socket ok!\n");
    //绑定地址信息
    int ret = bind(servFd, (struct sockaddr *)&servAddr, sizeof(servAddr));
    if(ret < 0)
    {
        perror("bind error!");
        close(servFd);
        return -1;
    }
    printf("bind ok!\n");
    //创建监听队列
    ret = listen(servFd, 10);
    if(ret < 0)
    {
        perror("listen error!");
        close(servFd);
        return -1;
    }
    printf("listening.....\n");
    while(1)
    {
        //接收连接请求
        int connFd = accept(servFd, NULL, NULL);
        if(connFd < 0)
        {
            perror("accept error!");
            close(servFd);
            return -1;
        }
        printf("accept ok!\n");

        pthread_t th;
        while(pthread_create(&th, NULL, threadFunc, &connFd) < 0);
    }
    //关闭套接字
    close(servFd);
    return 0;
}

































































































































客户端代码:

#include<stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>


int main ()
{
   
//定义结构体变量,该变量保存的服务器的地址信息,作为connect的参数
    struct sockaddr_in servAddr ;
   
memset (& servAddr , 0 , sizeof ( servAddr ));
   
servAddr . sin_family = PF_INET ;
   
servAddr . sin_port = htons ( 8888 );
   
servAddr . sin_addr . s_addr = inet_addr ( "127.0.0.1" );

   
//创建套接字
    int cliFd = socket ( PF_INET , SOCK_STREAM , 0 );
   
if ( cliFd < 0 )
   
{
       
perror ( "socket error!" );
       
return - 1 ;
   
}
   
printf ( "socket ok!\n" );
   
//发起连接请求
    int ret = connect ( cliFd , ( struct sockaddr *)& servAddr , sizeof ( servAddr ));
   
if ( ret < 0 )
   
{
       
perror ( "connect error!" );
       
close ( cliFd );
       
return - 1 ;
   
}
   
printf ( "connect ok!\n" );
   
char buf [ 1024 ];
   
while ( 1 )
   
{
       
memset ( buf , 0 , sizeof ( buf ));
       
printf ( "client:" );
       
gets ( buf );
       
if ( 0 == strcmp ( buf , "quit" ))
       
{
           
break ;
       
}
       
//发送消息
        ret = send ( cliFd , buf , sizeof ( buf ), 0 );
       
if ( ret < 0 )
       
{
           
perror ( "send error!" );
           
close ( cliFd );
           
return - 1 ;
       
}
       
printf ( "send ok!\n" );

       
memset ( buf , 0 , sizeof ( buf ));
       
recv ( cliFd , buf , sizeof ( buf ), 0 );
       
printf ( "recv from server %s\n" , buf );
   
}
   
//关闭套接字
    close ( cliFd );
   
return 0 ;
}











































    
   






































>>>IO多路复用的并发服务器
    适合于客户端数量较多,但是短连接的情况。

    
    
    
    
    
    
    
    
    
    
    
    
    
    
   
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值