网络编程下关于服务器模型的总结

LINUX下关于服务器模型的总结
服务器分为1:循环服务器
2:并发服务器
循环服务器:在同一时刻只能响应一个客户端的请求。
并发服务器:在同一时刻可以响应多个客户端的请求。

在循环服务器中,分为TCP服务器和 UDP服务器,循环服务器一般很少使用。
在并发服务器中,一般有多进程并发服务器,多线程服务器,IO多路复用并发服务器。
(1)多进程的并发服务器
只要有客户端连接服务器,服务器就创建子进程与客户端通信创建子进程后,父进程—-继续等待其他客户端的连接,子进程—-与客户端通信。这样就实现了多个客户端连接服务器的要求。特点:多进程服务器,比较浪费资源,适合于客户端数量较少,但是长连接的情况
(2)多线程的并发服务器
只要有客户端连接服务器,服务器就创建子线程与客户端通信
由于在创建子线程时,以及xian毁子线程时,比较浪费时间,一般可以使用线程池多线程存在的问题:存在资源竞争以及同步的问题
特点:适用于客户端较少,但是长时间连接的情况

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

代码具体实现多进程的并发服务器,process_server.c

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


void signfun(int sigNo);
int main()
{
    //定义Internet协议结构,服务器的端口号和IP地址
     struct sockaddr_in myaddr;
     memset(&myaddr,0,sizeof(myaddr));
     myaddr.sin_family = PF_INET;
     myaddr.sin_port = htons(1314);
     myaddr.sin_addr.s_addr = inet_addr("127.0.0.1");

  //1.创建套接字
   int serverId = socket(PF_INET,SOCK_STREAM,0);
   if(serverId<0)
   {
    perror("serverFd\n");
    return  -1;
   }
   printf("socket ok\n");
   //使用setsockopt防止使用地址错误
   int on=1;
   int set=setsockopt(serverId,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
   if(set<0)
   {
     printf("setsockopt\n");
     return -1;
   }

  //2.绑定地址信息
  int ret = bind(serverId,(struct sockaddr *)&myaddr,sizeof(myaddr));
  if(ret<0)
  {
    perror("bind\n");
    close(serverId);
    return -1;
  }
   printf("bind ok\n");
  //3.创建一个监听队列
    if(listen(serverId,10)<0)
    {
      perror("listen\n");
      close(serverId);
      return -1;
    }
    printf("listening....\n");
  //4.接受链接请求
  while(1)
  {
      printf("服务器正常工作中。。。\n");
      int conId=accept(serverId,NULL,NULL);//接收链接
      if(conId<0)
      {
          perror("accept\n");
          close(serverId);
          return -1;
      }
      printf("accept ok\n");
      pid_t pid;
      if((pid=fork())<0)//创建子进程处理链接请求,父进程继续监听
      {
          perror("fock\n");
          close(serverId);
          close (conId);
          return  -1;
      }
      else if(pid==0) //子进程里处理聊天
      {
          close(serverId);
          while(1)
          {
              char buf[1024];
              memset(buf,0,1024);
              int ret = recv(conId,buf,sizeof(buf),0);
              if(ret<0)
              {
                  perror("recv\n");
                  break;
              }
              if(ret ==0)
              {
                  printf("对方下线\n");
                  break;
              }
              printf("from xldclient:%s\n",buf);
              printf("xldserver:");
              gets(buf);
              if(strcmp(buf,"quit")==0)
              {
                  break;
              }
              ret = send(conId,buf,sizeof(buf),0);
              if(ret <0)
              {
                  perror("send\n");
                  break;
              }
          }
          close(conId);//关闭链接套接字
          exit(0);   //进程退出
      }
      else
      {
          close(conId); 
          signal(SIGCHLD,signfun);//信号处理函数,
                                 //子进程结束时会给父进程发送SIGCHLD
      }
  }
  //6.关闭套接字
  close(serverId);
  return 0;
}

void signfun(int sigNo)
{
   if(sigNo == SIGCHLD)
   {
    wait(NULL);
   }
   printf("子进程已结束\n");
}

多线程的并发服务器具体代码,pthread_server.c

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

void *profunC(void *arg);//线程处理函数的声明

int main()
{
    //定义Internet协议结构,服务器的端口号和IP地址
     struct sockaddr_in myaddr;
     memset(&myaddr,0,sizeof(myaddr));
     myaddr.sin_family = PF_INET;
     myaddr.sin_port = htons(1314);
     myaddr.sin_addr.s_addr = inet_addr("127.0.0.1");

  //1.创建套接字
   int serverId = socket(PF_INET,SOCK_STREAM,0);
   if(serverId<0)
   {
    perror("serverFd\n");
    return  -1;
   }
   printf("socket ok\n");
  //2.绑定地址信息
  int ret = bind(serverId,(struct sockaddr *)&myaddr,sizeof(myaddr));
  if(ret<0)
  {
    perror("bind\n");
    close(serverId);
    return -1;
  }
   printf("bind ok\n");
  //3.创建一个监听队列
    if(listen(serverId,10)<0)
    {
      perror("listen\n");
      close(serverId);
      return -1;
    }
    printf("listening....\n");
  //4.接受链接请求
  while(1)
  {
      printf("服务器正常工作中。。。\n");
      int conId=accept(serverId,NULL,NULL);
      if(conId<0)
      {
          perror("accept\n");
          close(serverId);
          return -1;
      }
      printf("accept ok\n");
      pthread_t th1;//主线程继续等待链接
      while(pthread_create(&th1,NULL,profunC,&conId)<0);
  }
  //6.关闭套接字
  close(serverId);
  return 0;
}

void *profunC(void *arg)
{
  int conId=*(int *)arg;
  //子线程完成通信
  while(1)
  {
      char buf[1024];
      memset(buf,0,1024);
      int ret = recv(conId,buf,sizeof(buf),0);
      if(ret<0)
      {
          perror("recv\n");
          break;
      }
      if(ret ==0)
      {
          printf("对方下线\n");
          break;
      }
         printf("from xldclient:%s\n",buf);
         printf("xldserver:");
         gets(buf);
         if(strcmp(buf,"quit")==0)
         {
             break;
         }
         ret = send(conId,buf,sizeof(buf),0);
      if(ret <0)
      {
          perror("send\n");
          break;
      }
   }
  close(conId);
  pthread_exit(NULL);
}

io多路复用的并发服务器的具体代码实现io_server.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/time.h>
#include <netinet/in.h>
int main()
{
    //定义Internet协议结构,服务器的端口号和IP地址
     struct sockaddr_in myaddr;
     memset(&myaddr,0,sizeof(myaddr));
     myaddr.sin_family = PF_INET;
     myaddr.sin_port = htons(1314);
     myaddr.sin_addr.s_addr = inet_addr("127.0.0.1");

  //1.创建套接字
     int serverId = socket(PF_INET,SOCK_STREAM,0);
     if(serverId<0)
     {
         perror("serverFd\n");
         return  -1;
     }
     printf("socket ok\n");
     //设置套接字选项避免地址使用错误
     int on=1;
      int st=setsockopt(serverId,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
      if(st<0)
      {
        perror("setsockopt error\n");
        close(serverId);
        return -1;
      }
  //2.绑定地址信息
     int ret = bind(serverId,(struct sockaddr *)&myaddr,sizeof(myaddr));
     if(ret<0)
     {
         perror("bind\n");
         close(serverId);
         return -1;
     }
     printf("bind ok\n");
  //3.创建一个监听队列
    if(listen(serverId,10)<0)
    {
        perror("listen\n");
        close(serverId);
        return -1;
    }
    printf("listening....\n");
    //1创建集合
    fd_set sebuf;
    //2清空集合
    FD_ZERO(&sebuf);
    //3将对应的文件描述符加入集合
    FD_SET(0,&sebuf);
    FD_SET(1,&sebuf);
    FD_SET(serverId,&sebuf);
    int maxfd=serverId;
    //使用seclect监视
    fd_set tmp ;
    int i;
    while(1)
    {
        printf("before select\n");
        tmp = sebuf;
        //select监视文件的变化
        int retu1=select(maxfd+1,&tmp,NULL,NULL,NULL);
        printf("retu1=%d\n",retu1);
        if(retu1<0)
        {
            perror("seclect\n");
            close(serverId);
            return -1;
        }
        for(i=0;i<=maxfd;i++)
        {
            if(FD_ISSET(i,&tmp))
            {
                if(i==0)
                {
                    printf("stdin\n");
                    char buf[1024]={0};
                    gets(buf);
                    printf("from stdin %s\n",buf);
                }
                else if(i==1)
                {
                    printf("stdout\n");
                }
                else if(i==serverId)
                {
                    //4.接受链接请求
                    int conId=accept(serverId,NULL,NULL);
                    if(conId<0)
                    {
                        perror("accept\n");
                        close(serverId);
                        return -1;
                    }
                    printf("accept ok\n");
                    FD_SET(conId,&sebuf);
                    if(conId > maxfd)
                    {
                        maxfd = conId;
                    }
                }
                else 
                    //5.收发消息
                {
                    char buf[1024];
                    memset(buf,0,1024);
                    ret = recv(i,buf,sizeof(buf),0);
                    if(ret<0)
                    {
                        perror("recv\n");
                        close(i);
                        return -1; 
                    }
                    if(ret==0)
                    {
                        printf("对方已下线\n");
                        close(i);
                        FD_CLR(i,&sebuf);
                        continue;
                    }
                    printf("from xldclient:%s\n",buf);
                    memset(buf,0,1024);
                    printf("xldserver:");
                    gets(buf);
                    ret = send(i,buf,sizeof(buf),0);
                    if(ret <0)
                    {
                        perror("send\n");
                        close(i);
                        return -1; 
                    }
                }
            }
        } 
    }
  //6.关闭套接字
  close(serverId);
  return 0;
}

代码写得略有粗糙,继续努力吧。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值