您的位置:首页 > 理论基础 > 计算机网络

Linux网络编程之循环服务器

2013-12-19 15:40 651 查看
1.介绍

Linux网络循环服务器是指逐个处理客户端的连接,处理完一个连接后再处理下一个连接,是一个串行处理的方式,比较适合时间服务器,DHCP服务器.对于TCP服务器来说,主要阻塞在accept函数,等待客户端的连接。而对于UDP服务器来说,主要阻塞在recv函数.

2.循环服务器模型

TCP循环服务器:
算法如下: 

        socket(...);

        bind(...);

        listen(...);

        while(1)

        {

                accept(...);

                read(...);

                process(...);

                write(...);

                close(...);//关闭客户端连接

              

       }

     close(....);//关闭服务器连接

UDP循环服务器:

  算法如下: 

   socket(...)

   bind(....);

  while(1){

  recvfrom(....);

  process(...);

  sendto(....);

 close(....);//关闭客户端连接 

 }

 close(....);//关闭服务器连接

从上面的流程可以看出,TCP循环服务器在accept处阻塞一直等待客户端的到来,而UDP循环服务器在recv处阻塞,等待客户端发送数据.

3. 循环服务器的例子

下面的程序是一个时间服务器,客户端发出TIME时间请求,服务器将本地时间返回给客户端.

(1)TCP循环服务器

服务器:

#include <stdio.h>

#include <string.h>

#include <stdlib.h>

#include <sys/socket.h>

#include <sys/types.h>

#include <time.h>

#include <netinet/in.h>

/**

TCP循环服务器

在accept处阻塞等待客户端的连接,并处理请求

**/

#define PORT 8888

#define BUFFERSIZE 1024

#define LISTEN 10

int main(int argc,char*argv[]){

  int s;

  int ret;

  int len;

  int size;

  int sc;

  time_t now;

  char buffer[BUFFERSIZE];

  struct sockaddr_in server_addr,client_addr;

  //建立流式套接字

  s=socket(AF_INET,SOCK_STREAM,0);

  if(s<0){

   perror("socket error");

   return -1;

 }

 //将地址绑定到套接字上

 memset(&server_addr,0,sizeof(server_addr));

 server_addr.sin_family=AF_INET;

 server_addr.sin_addr.s_addr=htonl(INADDR_ANY);

 server_addr.sin_port=htons(PORT);

 ret=bind(s,(struct sockaddr*)&server_addr,sizeof(server_addr));

 if(ret<0){

   perror("bind error");

   return -1;

 }

//监听队列的长度

 listen(s,LISTEN);

 len=sizeof(client_addr);

//接受客户端的请求

while(1){

   sc=accept(s,(struct sockaddr*)&client_addr,&len);//等待客户端的连接,client_addr存放的是客户端的信息

   memset(buffer,0,BUFFERSIZE);

   size=recv(sc,buffer,BUFFERSIZE,0);//利用套接字描述符sc进行通信

  if(size<0){

     perror("recv error");

     break;

  }

else if(!strncmp(buffer,"TIME",4)){

  now=time(NULL);

  sprintf(buffer,"%24s",ctime(&now));

  send(sc,buffer,strlen(buffer),0);

}

  close(sc);//关闭本次通信的客户端连接

}

close(s);

return 0;

}

客户端:

#include <stdio.h>

#include <string.h>

#include <stdlib.h>

#include <sys/socket.h>

#include <sys/types.h>

#include <time.h>

#include <netinet/in.h>

/**

循环服务器客户端程序

**/

#define PORT 8888

#define BUFFERSIZE 1024

int main(int argc,char*argv[]){

 int s;

 int ret;

 int size;

 struct sockaddr_in server_addr;

 char buffer[BUFFERSIZE];

 s=socket(AF_INET,SOCK_STREAM,0);

 if(s<0){

  perror("socket error");

  return -1;

}

bzero(&server_addr,sizeof(server_addr));

//将地址结构绑定到套接字

server_addr.sin_family=AF_INET;

server_addr.sin_port=htons(PORT);

server_addr.sin_addr.s_addr=htonl(INADDR_ANY);

//连接服务器

 ret=connect(s,(struct sockaddr*)&server_addr,sizeof(server_addr));

 if(ret==-1){

  perror("connect error");

  return -1;

}

memset(buffer,0,BUFFERSIZE);

strcpy(buffer,"TIME");

size=send(s,buffer,strlen(buffer),0);

if(size<0){

  perror("send error");

  return -1;

}

memset(buffer,0,BUFFERSIZE);

size=recv(s,buffer,BUFFERSIZE,0);

if(size<0){

  perror("recv error");

  return;

}

printf("%s",buffer);

close(s);

return 0;

}

运行结果:
[root@localhost 14章服务器模式]# ./circle-tcpc14

Sat Feb 18 09:44:31 2012

(2)UDP循环服务器

服务器:

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <time.h>

#include <netinet/in.h>

#include <sys/socket.h>

#include <sys/types.h>

/**

UDP循环服务器

原理:服务器在recv函数与处理业务之间轮循处理

**/

#define PORT 8888

#define BUFFERSIZE 1024

int main(int argc,char*argv[]){

int s;

struct sockaddr_in server_addr,client_addr;//分别表示客户端地址与服务器端地址

time_t now;

int ret;

 int size;

char buffer[BUFFERSIZE];

//建立数报套接字

s=socket(AF_INET,SOCK_DGRAM,0);//数据报

if(s<0){

   perror("socket error");

  return -1;

}

//地址绑定

bzero(&server_addr,sizeof(server_addr));//地址结构清0

server_addr.sin_family=AF_INET;

server_addr.sin_addr.s_addr=htonl(INADDR_ANY);

server_addr.sin_port=htons(PORT);

ret=bind(s,(struct sockaddr*)&server_addr,sizeof(server_addr));

if(ret==-1){

   perror("bind error");

   return -1;

}

//数据报套接字没有流量控制所以没有监听listen,也没有三次握手,所以没有接受连接accept

while(1){

 memset(buffer,0,BUFFERSIZE);//清0

 int len=sizeof(client_addr);

 size=recvfrom(s,buffer,BUFFERSIZE,0,(struct sockaddr*)&client_addr,&len);

 if(size<=0){

   perror("recvfrom");

}else{

  if(!strncmp(buffer,"TIME",4)){//判断是否是合法数据

      memset(buffer,0,BUFFERSIZE);

      now=time(NULL);//获得当前时间

      sprintf(buffer,"%24s",ctime(&now));//ctime所指向的最后一个字符是\n

      sendto(s,buffer,strlen(buffer),0,(struct sockaddr*)&client_addr,len);//发送数据,第3项表示发送数据的长度

}

}

}

 close(s);

 return 0;

}

客户端:

#include <stdio.h>

#include <string.h>

#include <stdlib.h>

#include <sys/socket.h>

#include <sys/types.h>

#include <time.h>

#include <netinet/in.h>

/**

UDP客店端,客户端向服务器发送时间请求,服务器返回相应的时间

**/

#define PORT 8888

#define BUFFERSIZE 1024

int main(int argc,char*argv[]){

  int s;//套接字描述符

  int ret;//建立套接字的返回值

  int size;

  struct sockaddr_in server_addr;//地址结构

  int len;

  char buffer[BUFFERSIZE];

  s=socket(AF_INET,SOCK_DGRAM,0);//建立流式套接字 

  if(s<0){

    perror("socket error");

    return -1;

  }   

 bzero(&server_addr,sizeof(server_addr));

  server_addr.sin_family=AF_INET;

  server_addr.sin_addr.s_addr=htonl(INADDR_ANY);

  server_addr.sin_port=htons(PORT);

  memset(buffer,0,BUFFERSIZE);

  strcpy(buffer,"TIME");

 //向服务器发送数据

 size=sendto(s,buffer,strlen(buffer),0,(struct sockaddr*)&server_addr,sizeof(server_addr));

 if(size<0){

   perror("sendto error");

   return -1;

 }

 //从服务器接收数据

 len=sizeof(server_addr);

  size=recvfrom(s,buffer,BUFFERSIZE,0,(struct sockaddr*)&server_addr,&len);

 if(size<0){

   perror("recvfrom error");

  return -1;

 }

  //write(1,buffer,size);

  printf("%s\n",buffer);

 close(s);

 return 0;

}

运行结果:

[root@localhost 14章服务器模式]# ./circle-udpc14

Sat Feb 18 09:59:22 2012

总结:本文主要介绍了循环服务器的算法流程,并且给出了TCP与UDP循环服务器实例.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: