• socket编写简单回显server


    socket在公司代码中应用比较广,比如接口调用的IPCRPC机制,经常看到这样的代码,但是一直也没有动手写过。

    在某个比较大的进程中创建一个子进程,由于父子进程复制会浪费内存,可以将创建进程的命令通过socket发送到另一个轻量级的进程来创建。

    在lighttpd和airplay的源码中,socket的框架是类似的。

    下面参照lighttpd和airplay写个简单的回显server,以后有空再完善。

    server.c

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <errno.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <sys/select.h>
    #include <sys/time.h>
    #include <unistd.h>
    #include <fcntl.h>

    //#define USE_UNIX_SOCKET
    #define USE_IPV4_SOCKET
    #ifdef USE_UNIX_SOCKET
    #include <sys/un.h>
    const char * host = "/tmp/fellow.srv.un.addr";
    #endif
    #ifdef USE_IPV4_SOCKET
    const char *host = "127.0.0.1";
    const int port = 9090;
    #endif
    #define FDEVENT_IN (1<<0)
    #define FDEVENT_OUT (1<<1)
    #define FDEVENT_ERR (1<<2)

    typedef struct _FdEvent{
      int maxFd;
      fd_set select_listen_read_fd;//监听fd
      fd_set select_listen_write_fd;
      fd_set select_listen_err_fd;
      fd_set select_set_read_fd;//每次加入fd到select_set_*_fd,在select前将值赋给监听fd,可以不必每次遍历来初始化监听fd
      fd_set select_set_write_fd;
      fd_set select_set_err_fd;
    }FdEvent;
    typedef void (*Handle)(void *context);
    typedef struct _SockSource{//每一个监听到的socket对应一个SockSource
      int sock;
      int sockType;
      Handle handle;//当sock有时间发生时,调用handle处理
    struct _SockSource *next;
    }SockSource;
    SockSource *gSockSourceList = NULL;
    FdEvent gFdEvent;

    SockSource *createSockSource(int sock, int sockType, Handle handle)
    {
      SockSource *sockSource = (SockSource *)malloc(sizeof(SockSource));
      sockSource->sock = sock;
      sockSource->sockType = sockType;
      sockSource->handle = handle;
      sockSource->next = NULL;
      return sockSource;
    }

    void addToSockSourceList(SockSource *sockSource)
    {
      if (gSockSourceList == NULL)
      {
        gSockSourceList = sockSource;
      }
      else
      {
        sockSource->next = gSockSourceList;
        gSockSourceList = sockSource;
      }
    }

    void removeFromSockSourceList(SockSource *sockSource)
    {
      if (NULL == gSockSourceList) return;
      if (gSockSourceList == sockSource)
      {
        gSockSourceList = sockSource;
        if (sockSource) free(sockSource);
      }
      else
      {
        SockSource *curSockSource = gSockSourceList;
        SockSource *nextSockSource = gSockSourceList->next;
        for (; nextSockSource != NULL; nextSockSource = nextSockSource->next)
        {
          if (nextSockSource == sockSource)
          {
            curSockSource->next = nextSockSource->next;
            if(sockSource) free(sockSource);
            break;
          }
          curSockSource = nextSockSource;
        }
      }
    }


    void fdevent_select_reset(FdEvent *ev)
    {
      FD_ZERO(&(ev->select_set_read_fd));
      FD_ZERO(&(ev->select_set_write_fd));
      FD_ZERO(&(ev->select_set_err_fd));
      ev->maxFd = -1;
    }

    void fdevent_select_set(FdEvent *ev, int fd, int event)
    {
      if (fd > (int)FD_SETSIZE) return;
      if (event & FDEVENT_IN)
      {
        FD_SET(fd, &(ev->select_set_read_fd));
      }
      else
      {
        FD_CLR(fd, &(ev->select_set_read_fd));
      }
      if (event & FDEVENT_OUT)
      {
        FD_SET(fd, &(ev->select_set_write_fd));
      }
      else
      {
        FD_CLR(fd, &(ev->select_set_write_fd));
      }
      if (event & FDEVENT_ERR)
      {
        FD_SET(fd, &(ev->select_set_err_fd));
      }
      else
      {
        FD_CLR(fd, &(ev->select_set_err_fd));
      }
      if (fd > ev->maxFd) ev->maxFd = fd;
    }


    int fdevent_select_poll(FdEvent *ev, int time_ms)
    {
      struct timeval tv;
      tv.tv_sec = time_ms /1000;
      tv.tv_usec = (time_ms % 1000) * 1000;
      ev->select_listen_read_fd = ev->select_set_read_fd;
      ev->select_listen_write_fd = ev->select_set_write_fd;
      ev->select_listen_err_fd = ev->select_set_err_fd;
      return select(ev->maxFd + 1, &(ev->select_listen_read_fd),&(ev->select_listen_write_fd),&(ev->select_listen_err_fd), &tv);
    }


    void accept_handle(void *context)
    {
      SockSource *clientSource = (SockSource *)context;
      char rcvBuf[1024];
      char sndBuf[1024];
      memset(&rcvBuf, 0, sizeof(rcvBuf));
      memset(&sndBuf, 0, sizeof(sndBuf));
      int byteRcv = recv(clientSource->sock, rcvBuf, sizeof(rcvBuf), 0);
      if (byteRcv > 0)
      {
        printf("rcv data: %s, len: %d ", rcvBuf, byteRcv);
        snprintf(sndBuf, sizeof(sndBuf), "server rcv %s ", rcvBuf);
        send(clientSource->sock, sndBuf, strlen(sndBuf)+1, 0);
      }
      else
      {
        printf("rcv fail, errno:%d ", errno);
        fdevent_select_set(&gFdEvent, clientSource->sock, 0);
        removeFromSockSourceList(clientSource);
      }
    }


    void listen_handle(void *context)
    {
      SockSource *listenSource = (SockSource *)context;
      int client_sock = -1;
      size_t addr_len = 0;
    #ifdef USE_UNIX_SOCKET
      struct sockaddr_un client_addr;
      addr_len = strlen(host) + sizeof(client_addr.sun_family);
    #endif
    #ifdef USE_IPV4_SOCKET
      struct sockaddr_in client_addr;
      addr_len = sizeof(struct sockaddr_in);
    #endif
      if (-1 == (client_sock = accept(listenSource->sock, (struct sockaddr*)&client_addr, &addr_len)))
      {
        switch(errno)
        {
          case EAGAIN:
          #if EAGAIN != EWOULDBLOCK
          case EWOULDBLOCK;
          #endif
          break;
          default:
          printf("accept fail, errno:%d", errno);
          break;
        }
      }
      else
      {
        fdevent_select_set(&gFdEvent, client_sock, FDEVENT_IN);
        SockSource *clientSource = createSockSource(client_sock, (int)FDEVENT_IN, accept_handle);
        addToSockSourceList(clientSource);
      }
    }

    int setup_listen_socket()
    {
      int sock = -1;
      socklen_t addr_len;
    #ifdef USE_UNIX_SOCKET
      struct sockaddr_un srv_addr;
      srv_addr.sun_family = AF_UNIX;
      if (-1 == (sock = socket(AF_UNIX, SOCK_STREAM, 0)))
      {
        printf("un socket fail, errno:%d ", errno);
        goto err;
      }
      size_t hostLen = strlen(host) + 1;
      memcpy(srv_addr.sun_path, host, hostLen);
      addr_len = hostLen + sizeof(srv_addr.sun_family);
    #endif
    #ifdef USE_IPV4_SOCKET
      struct sockaddr_in srv_addr;
      memset(&srv_addr, 0, sizeof(struct sockaddr_in));
      srv_addr.sin_family = AF_INET;
      if (-1== (sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)))
      {
        printf("in socket fail, errno:%d ", errno);
        goto err;
      }
      int val = 1;
      if (-1== setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)))
      {
        printf("setsockopt fail, errno:%d ", errno);
        goto err;
      }

      if (0 == inet_aton(host, &(srv_addr.sin_addr)))
      {
        printf("inet_aton fail, errno:%d ", errno);
        goto err;
      }
      srv_addr.sin_port = htons(port);
      addr_len = sizeof(struct sockaddr_in);
    #endif
      if (0 != bind(sock, (struct sockaddr*)&srv_addr, addr_len))
      {
        printf("bind fail, errno:%d ", errno);
        goto err;
      }
      if (0 != listen(sock, 10))
      {
        printf("inet_aton fail, errno:%d ", errno);
        goto err;
      }
      fdevent_select_set(&gFdEvent, sock, FDEVENT_IN);
      SockSource *listenSource = createSockSource(sock, (int)FDEVENT_IN, listen_handle);
      addToSockSourceList(listenSource);
      return sock;
    err:
      if (-1 != sock)
      {
        close(sock);
      }
      return -1;
    }

    void main(void)
    {
      int sock = -1;
      int numOfEvent = 0;
      fdevent_select_reset(&gFdEvent);
      if(-1 == (sock = setup_listen_socket()))
      {
      return;
      }
      printf("listenning sock:%d ", sock);
      while (1)
      {
        int timeout_ms = 1000;
        numOfEvent = fdevent_select_poll(&gFdEvent, timeout_ms);
        if (numOfEvent > 0)
        {
          SockSource *source = NULL;
          for (source = gSockSourceList; source != NULL; source = source->next)
          {
            switch(source->sockType)
            {
              case FDEVENT_IN:
              if (FD_ISSET(source->sock, &(gFdEvent.select_listen_read_fd)))
              {
                source->handle(source);
                numOfEvent--;
              }
              break;
              case FDEVENT_OUT:
              if (FD_ISSET(source->sock, &(gFdEvent.select_listen_write_fd)))
              {
                source->handle(source);
                numOfEvent--;
              }
              break;
              case FDEVENT_ERR:
              if (FD_ISSET(source->sock, &(gFdEvent.select_listen_err_fd)))
              {
                source->handle(source);
                numOfEvent--;
              }
              break;
            }
          }
        }
      }
    }

    client端测试代码:

    #include <sys/types.h>
    #include <sys/socket.h>
    #include <sys/un.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>

    #define USE_IPV4_SOCKET
    //#define USE_UNIX_SOCKET
    #ifdef USE_UNIX_SOCKET
    #include <sys/un.h>
    const char * host = "/tmp/fellow.srv.un.addr";
    #endif
    #ifdef USE_IPV4_SOCKET
    const char *host = "127.0.0.1";
    const int port = 9090;
    #endif

    void main(void)
    {
      int sock = -1;
      char sndBuf[1024];
      char rcvBuf[1024];
      socklen_t addr_len;
    #ifdef USE_UNIX_SOCKET
      struct sockaddr_un srv_addr;
      srv_addr.sun_family = AF_UNIX;
      if (-1 == (sock = socket(AF_UNIX, SOCK_STREAM, 0)))
      {
        printf("un socket fail, errno:%d ", errno);
        goto err;
      }
      size_t hostLen = strlen(host) + 1;
      memcpy(srv_addr.sun_path, host, hostLen);
      addr_len = hostLen + sizeof(srv_addr.sun_family);
    #endif
    #ifdef USE_IPV4_SOCKET
      struct sockaddr_in srv_addr;
      memset(&srv_addr, 0, sizeof(struct sockaddr_in));
      srv_addr.sin_family = AF_INET;
      if (-1== (sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)))
      {
        printf("in socket fail, errno:%d ", errno);
        goto err;
      }
      if (0 == inet_aton(host, &(srv_addr.sin_addr)))
      {
        printf("inet_aton fail, errno:%d ", errno);
        goto err;
      }
      srv_addr.sin_port = htons(port);
      addr_len = sizeof(struct sockaddr_in);

    #endif
      if (-1 == connect(sock, (struct sockaddr*)&srv_addr, addr_len))
      {
        printf("connect fail, errno:%d ", errno);
        goto err;
      }
      int running = 1;
      int count = 0;
      while (running)
      {
        printf("Send your msg to server, finish with end! ");
        fgets(sndBuf, sizeof(sndBuf), stdin);
        int dataLen = strlen(sndBuf) + 1;
        if (-1 == send(sock, (void*)&sndBuf, dataLen, 0))
        {
          printf("send fail, errno:%d ", errno);
          goto err;
        }
        if(!strncmp(sndBuf, "end", strlen("end")))
        {
          running = 0;
        }
        if (-1 == recv(sock, (void*)&rcvBuf, sizeof(rcvBuf), 0))
        {
          printf("recv fail, errno:%d ", errno);
          goto err;
        }
        printf("data from server: %s ", rcvBuf);
        count++;

      }
    err:
      if(-1 != sock) close(sock);
    }

    client端测试结果:

    server端log

  • 相关阅读:
    Java常见问题汇总
    前端url参数中带有callback并产生错误
    shiro中ecache-core版本引起的异常
    深入SpringMVC注解
    导出表格数据到excel并下载(HSSFWorkbook版)
    layui数据表格及分页
    签名的生成
    程序的健壮性Robustness
    ASP.NET MVC中注册Global.asax的Application_Error事件处理全局异常
    生成二维码功能
  • 原文地址:https://www.cnblogs.com/fellow1988/p/6166206.html
Copyright © 2020-2023  润新知