最近在玩android,突然想做一个私人聊天工具,缺乏一个服务器,于是自己想写一个c实现的daemon select server

来源:互联网 发布:icloud恢复备份mac 编辑:程序博客网 时间:2024/05/16 07:09

我喜欢站在巨人的肩膀上来做事,因为学习的道路是曲折的,你不可能将所有的东西都搞懂搞透了才去做一件事情,那样,你永远做不了大事。思路大概是这样的

1、找一个daemon程序来看看,了解起原理。

2、找一个select server程序来看看,了解起原理。

3、将两者融合起来,就是一个daemon 的select server了。

为什么要daemon,因为,我们server脱离终端,不想因为终端连接断开啥的一些而导致我们的server程序退出。当然,讲得有些不够准确,但是好处多多,大家可以去google所stackvoer上找。

为什么要用select而不用epoll,没有错,epoll确实比select要更加好用,但是,出于学习的目的,我觉得select,poll,epoll都该了解下,时间有限,写个select玩玩,epoll强大,以后server升级的方向就是换成epoll,还有一点考虑是epoll是linux才有的,而且貌似先前linux版本还没有,unix上,据我看到的一个较老的资料上讲,没有epoll,不管怎么样,这三个都是系统调用,也就是内核帮我们去做的一件事。


程序代码如下,这是直接可以在linux上编译通过的

g++ -g -o select_server select_server.cpp

./select_server 9988

ps -ef |grep select_server

如果成功启动,就可以看到select_server 这个进程了。

/*UNIX Daemon Server Programming Sample ProgramLevent Karakas <levent at mektup dot at> May 2001To compile: cc -o exampled examped.cTo run:   ./exampledTo test daemon: ps -ef|grep exampled (or ps -aux on BSD systems)To test log:  tail -f /tmp/exampled.logTo test log:  tail -f /tmp/select_server_v2.logTo test signal: kill -HUP `cat /tmp/exampled.lock`To terminate: kill `cat /tmp/exampled.lock`*/#include <stdio.h>#include <errno.h>#include <stdlib.h>#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include <arpa/inet.h>#include <netinet/in.h>#include <netdb.h>#include <fcntl.h>#include <signal.h>#include "string"#define MAXMSG  512#define RUNNING_DIR "/tmp"#define LOCK_FILE "exampled.lock"#define LOG_FILE  "exampled.log"#define SEREVER_CONNET_LOG "select_server_v2.log"/******************start of daemon ******************************/void log_message(char *filename,char *message){  FILE *logfile;  logfile=fopen(filename,"a");  if(!logfile) return;  fprintf(logfile,"%s\n",message);  fclose(logfile);}void signal_handler(int sig){  switch(sig) {  case SIGHUP:    log_message(LOG_FILE,"hangup signal catched");    break;  case SIGTERM:    log_message(LOG_FILE,"terminate signal catched");    exit(0);    break;  }}void daemonize(){  int i,lfp;  char str[10];  if(getppid()==1) return; /* already a daemon */  i=fork();  if (i<0) exit(1); /* fork error */  if (i>0) exit(0); /* parent exits */  /* child (daemon) continues */  setsid(); /* obtain a new process group */  for (i=getdtablesize();i>=0;--i) close(i); /* close all descriptors */  i=open("/dev/null",O_RDWR); dup(i); dup(i); /* handle standart I/O */  umask(027); /* set newly created file permissions */  chdir(RUNNING_DIR); /* change running directory */  lfp=open(LOCK_FILE,O_RDWR|O_CREAT,0640);  if (lfp<0){    perror("can not open!");    exit(1); /* can not open */  }   if (lockf(lfp,F_TLOCK,0)<0){    perror("can not lock!");    exit(0); /* can not lock */  }   /* first instance continues */  sprintf(str,"%d\n",getpid());  write(lfp,str,strlen(str)); /* record pid to lockfile */  signal(SIGCHLD,SIG_IGN); /* ignore child */  signal(SIGTSTP,SIG_IGN); /* ignore tty signals */  //signal(SIGTTOU,SIG_IGN);  //signal(SIGTTIN,SIG_IGN);  signal(SIGHUP,signal_handler); /* catch hangup signal */  signal(SIGTERM,signal_handler); /* catch kill signal */}/******************end of daemon ******************************//***********************make select server **********************/int make_socket (uint16_t port){ int sock; struct sockaddr_in name; /* Create the socket. */ sock = socket (PF_INET, SOCK_STREAM, 0); if (sock < 0)   {     perror ("socket");     exit (EXIT_FAILURE);   } /* Give the socket a name. */ name.sin_family = AF_INET; name.sin_port = htons (port); name.sin_addr.s_addr = htonl (INADDR_ANY); if (bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0)   {     perror ("bind");     exit (EXIT_FAILURE);   } return sock;}      int read_from_client (int filedes){  char buffer[MAXMSG];  char log_msg[MAXMSG+128];  int nbytes;  nbytes = read (filedes, buffer, MAXMSG);  if (nbytes < 0)  {    /* Read error. */    perror ("read");    exit (EXIT_FAILURE);  } else if (nbytes == 0)    /* End-of-file. */    return -1; else   {     /* Data read. */    memset(log_msg,0x00,sizeof(log_msg));    sprintf(log_msg,"Server :got message [%s]\n",buffer );    log_message(SEREVER_CONNET_LOG,log_msg);    /*Data write**/    if(write(filedes,buffer,nbytes)==-1){      perror("server write error!");      exit(EXIT_FAILURE);    }    return 0;   }}     int main (int count, char *strings[]){ int sock; fd_set active_fd_set, read_fd_set; int i; struct sockaddr_in clientname; size_t size; int port; if ( count != 2 )  {    printf("usage: %s <port>\n", strings[0]);    exit(0);  }  port=atoi(strings[1]);  // make server to be a daemon server;  daemonize(); /* Create the socket and set it up to accept connections. */ sock = make_socket (port); if (listen (sock, 1) < 0)  {   perror ("listen");   exit (EXIT_FAILURE);  }   /* Initialize the set of active sockets. */ FD_ZERO (&active_fd_set); FD_SET (sock, &active_fd_set); while (1)   {     /* Block until input arrives on one or more active sockets. */     read_fd_set = active_fd_set;     if (select (FD_SETSIZE, &read_fd_set, NULL, NULL, NULL) < 0)       {         perror ("select");         exit (EXIT_FAILURE);       }     /* Service all the sockets with input pending. */     for (i = 0; i < FD_SETSIZE; ++i)       if (FD_ISSET (i, &read_fd_set))         {           if (i == sock)             {               /* Connection request on original socket. */               int new_fd;               size = sizeof (clientname);               new_fd = accept (sock,                             (struct sockaddr *) &clientname,                             &size);               if (new_fd < 0)                 {                   perror ("accept");                   exit (EXIT_FAILURE);                 }               fprintf (stderr,                        "Server: connect from host %s, port %hd.\n",                        inet_ntoa (clientname.sin_addr),                        ntohs (clientname.sin_port));               FD_SET (new_fd, &active_fd_set);             }           else             {               /* Data arriving on an already-connected socket. */               if (read_from_client (i) < 0)                 {                   close (i);                   FD_CLR (i, &active_fd_set);                 }             }         }   }}/*end eof */

至于这么测试 ,telnet XXX.XXX.XXX.XXX 9988

顺便介绍一个命令,strace ,这个可以跟踪下系统调用。如果服务器没启动起来的话,用它来看看,到了那一步,我开始调的时候,貌似到select是出了点问题的。

呵呵,

0 0