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

来源:互联网 发布:c语言转汇编 编辑:程序博客网 时间:2024/05/24 01:41

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;}

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

原创粉丝点击