TCP网络服务器模型

来源:互联网 发布:闰年的判断c语言 编辑:程序博客网 时间:2024/05/22 08:13

服务器模型

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>

intmain()
{
   
//定义结构体变量,作为bind函数的参数
   structsockaddr_inservAddr;
   
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
   intservFd=socket(PF_INET,SOCK_STREAM,0);
   
if(servFd<0)
   
{
       
perror("socket error!");
       
return-1;
   
}
   
printf("socket ok!\n");
   
//绑定地址信息
   intret=bind(servFd,(structsockaddr*)&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)
   
{
       
//接收连接请求
       intconnFd=accept(servFd,NULL,NULL);
       
if(connFd<0)
       
{
           
perror("accept error!");
           
close(servFd);
           
return-1;
       
}
       
printf("accept ok!\n");

       
charbuf[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);
   
return0;
}









































































































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


intmain()
{
   
//定义结构体变量,该变量保存的服务器的地址信息,作为connect的参数
   structsockaddr_inservAddr;
   
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");

   
//创建套接字
   intcliFd=socket(PF_INET,SOCK_STREAM,0);
   
if(cliFd<0)
   
{
       
perror("socket error!");
       
return-1;
   
}
   
printf("socket ok!\n");
   
//发起连接请求
   intret=connect(cliFd,(structsockaddr*)&servAddr,sizeof(servAddr));
   
if(ret<0)
   
{
       
perror("connect error!");
       
close(cliFd);
       
return-1;
   
}
   
printf("connect ok!\n");
   
charbuf[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>

voidsigFunc(intsigNo)
{
   
if(sigNo==SIGCHLD)
   
{
       
wait(NULL);
   
}
}

intmain()
{
   
//定义结构体变量,作为bind函数的参数
   structsockaddr_inservAddr;
   
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
   intservFd=socket(PF_INET,SOCK_STREAM,0);
   
if(servFd<0)
   
{
       
perror("socket error!");
       
return-1;
   
}
   
printf("socket ok!\n");
   
//绑定地址信息
   intret=bind(servFd,(structsockaddr*)&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)
   
{
       
//接收连接请求
       intconnFd=accept(servFd,NULL,NULL);
       
if(connFd<0)
       
{
           
perror("accept error!");
           
close(servFd);
           
return-1;
       
}
       
printf("accept ok!\n");

       
//创建子进程
       pid_tpid;
       
while((pid=fork())<0);
       
if(0==pid)
       
{
           
close(servFd);
           
charbuf[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;
               
}
               
elseif(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);
   
return0;
}




















































































































































客户端代码:

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


intmain()
{
   
//定义结构体变量,该变量保存的服务器的地址信息,作为connect的参数
   structsockaddr_inservAddr;
   
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");

   
//创建套接字
   intcliFd=socket(PF_INET,SOCK_STREAM,0);
   
if(cliFd<0)
   
{
       
perror("socket error!");
       
return-1;
   
}
   
printf("socket ok!\n");
   
//发起连接请求
   intret=connect(cliFd,(structsockaddr*)&servAddr,sizeof(servAddr));
   
if(ret<0)
   
{
       
perror("connect error!");
       
close(cliFd);
       
return-1;
   
}
   
printf("connect ok!\n");
   
charbuf[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);
   
return0;
}



























































   
























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

服务器代码:
#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)
{
   
intconnFd=*((int*)arg);
   
charbuf[1024]={0};
   
while(1)
   
{
       
memset(buf,0,sizeof(buf));
       
//接收消息
       intret=recv(connFd,buf,sizeof(buf),0);
       
if(ret<0)
       
{
           
perror("recv error!");
           
close(connFd);
           
pthread_exit((void*)-1);
       
}
       
elseif(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>


intmain()
{
   
//定义结构体变量,该变量保存的服务器的地址信息,作为connect的参数
   structsockaddr_inservAddr;
   
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");

   
//创建套接字
   intcliFd=socket(PF_INET,SOCK_STREAM,0);
   
if(cliFd<0)
   
{
       
perror("socket error!");
       
return-1;
   
}
   
printf("socket ok!\n");
   
//发起连接请求
   intret=connect(cliFd,(structsockaddr*)&servAddr,sizeof(servAddr));
   
if(ret<0)
   
{
       
perror("connect error!");
       
close(cliFd);
       
return-1;
   
}
   
printf("connect ok!\n");
   
charbuf[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);
   
return0;
}











































    
   






































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

    
    
    
    
    
    
    
    
    
    
    
    
    
    
   
原创粉丝点击