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\n", rcvBuf, byteRcv);
    snprintf(sndBuf, sizeof(sndBuf), "server rcv %s\n", rcvBuf);
    send(clientSource->sock, sndBuf, strlen(sndBuf)+1, 0);
  }
  else
  {
    printf("rcv fail, errno:%d\n", 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\n", 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\n", errno);
    goto err;
  }
  int val = 1;
  if (-1== setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)))
  {
    printf("setsockopt fail, errno:%d\n", errno);
    goto err;
  }

  if (0 == inet_aton(host, &(srv_addr.sin_addr)))
  {
    printf("inet_aton fail, errno:%d\n", 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\n", errno);
    goto err;
  }
  if (0 != listen(sock, 10))
  {
    printf("inet_aton fail, errno:%d\n", 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\n", 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\n", 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\n", errno);
    goto err;
  }
  if (0 == inet_aton(host, &(srv_addr.sin_addr)))
  {
    printf("inet_aton fail, errno:%d\n", 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\n", errno);
    goto err;
  }
  int running = 1;
  int count = 0;
  while (running)
  {
    printf("Send your msg to server, finish with end!\n");
    fgets(sndBuf, sizeof(sndBuf), stdin);
    int dataLen = strlen(sndBuf) + 1;
    if (-1 == send(sock, (void*)&sndBuf, dataLen, 0))
    {
      printf("send fail, errno:%d\n", 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\n", errno);
      goto err;
    }
    printf("data from server: %s\n", rcvBuf);
    count++;

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

client端测试结果:

server端log

socket编写简单回显server的更多相关文章

  1. 二、socket编写简单BIO的HTTP服务器

    一.目标 诸如tomcat等web服务器中间件简化了我们web的开发成本,但有时候我们或许并不需要这么一个完备的服务器,只是希望做一个简单地处理或者做特殊用途的服务器. 本文将提供一个HTTP的服务器 ...

  2. 关于Socket编写简单聊天工具的总结(原创)

    这段时间再看socket编程,虽然现在是刚刚接触,但是还是忍不住想写一篇总结,来激励自己努力学习,写的不好的地方,还请大家指教啊! 下面针对一个简单的发送消息和文件的程序说说吧.   首先是服务器需要 ...

  3. Python网络编程——编写一个简单的回显客户端/服务器应用

    今天将python中socket模块的基本API学习完后,照着书上的实例编写一个套接字服务器和客户端.采用python3.5版本,在注释中会标明python2和python3的不同之处. 1.代码 ( ...

  4. libevent的使用方法--回显服务器的简单实例

    #include <event.h> #include <sys/types.h> #include <sys/socket.h> #include <net ...

  5. 用Python编写一个简单的Http Server

    用Python编写一个简单的Http Server Python内置了支持HTTP协议的模块,我们可以用来开发单机版功能较少的Web服务器.Python支持该功能的实现模块是BaseFTTPServe ...

  6. NodeJS+Express+MongoDB 简单实现数据录入及回显展示【适合新人刚接触学习】

    近期在看NodeJS相关 不得不说NodeJS+Express 进行网站开发是很不错,对于喜欢玩JS的来说真是很好的一种Web开发组合 在接触NodeJS时受平时Java或者C#中API接口等开发的思 ...

  7. 编写一个简单的Web Server

    编写一个简单的Web Server其实是轻而易举的.如果我们只是想托管一些HTML页面,我们可以这么实现: 在VS2013中创建一个C# 控制台程序 编写一个字符串扩展方法类,主要用于在URL中截取文 ...

  8. Struts2第十一篇【简单UI标签、数据回显】

    Struts2UI标签 Sturts2为了简化我们的开发,也为我们提供了UI标签-也就是显示页面的标签-.. 但是呢,Struts2是服务端的框架,因此使用页面的标签是需要在服务器端解析然后再被浏览器 ...

  9. Linux终端下简单的登录程序 密码不回显

    在Linux进行登录是输入密码不会被回显,所以我也写了个简单的登入程序,使得在输入密码时不再进行回显. #include <stdio.h> #include <stdlib.h&g ...

随机推荐

  1. Oracle 性能相关常用脚本(SQL)

    在缺乏的可视化工具来监控数据库性能的情形下,常用的脚本就派上用场了,下面提供几个关于Oracle性能相关的脚本供大家参考.以下脚本均在Oracle 10g测试通过,Oracle 11g可能要做相应调整 ...

  2. ProgressBar及其子类

    1.ProgressBar(进度条组件) 派生了两个常用的组件:SeekBar和RatingBar. <1>通过style属性可以为ProgressBar指定风格,该属性可支持如下几个属性 ...

  3. [禅悟人生]"执著"是自缚的茧

    宋代苏东坡和佛印禅师是好朋友,他们习惯拿对方开玩笑.有一天,苏东坡到金山寺和佛印禅师打坐参禅,苏东坡觉得身心通畅,于是问禅师道:“禅师!你看我坐的样子怎么样?” “好庄严,像一尊佛!” 苏东坡听了非常 ...

  4. 设置TextView控件的背景透明度和字体透明度

    TextView tv = (TextView) findViewById(R.id.xx); 第1种:tv.setBackgroundColor(Color.argb(255, 0, 255, 0) ...

  5. mongo 安装

    mongo 安装: 1.按照 https://docs.mongodb.com/manual/tutorial/install-mongodb-on-red-hat/ 安装 2.安装成功后创建用户 d ...

  6. HDU5808Price List Strike Back (BestCoder Round #86 E) cdq分治+背包

    严格按题解写,看能不能形成sum,只需要分割当前sum怎么由两边组成就好 #include <cstdio> #include <cstring> #include <c ...

  7. mysql存贮过程编写

    这篇并不是说如何去写存贮过程,只是自己以前在测试过程中主要是查看,获取数据库里的数据,偶尔删除一些脏数据.然后这次因为手动测试组想做一个批量审批的测试,因为流程繁杂,因此想用一种快速的方式去做,于是就 ...

  8. Android百度地图开发(三)范围搜索

    // 1.新建项目 将地图API添加进classpath中: 2.在activity_main.xml中添加一个MapView,用来显示地图: <LinearLayout xmlns:andro ...

  9. NewtonPrincipia --- 公理或运动的定律 --- 系理二

    NewtonPrincipia --- 公理或运动的定律 --- 系理二 自然哲学的数学原理>公理或运动的定律>系理II 平行四边形ABCD,那么:直接的力AD由任意的力AB和BD合成,直 ...

  10. 【DWT笔记】基于小波变换的降噪技术

    [DWT笔记]基于小波变换的降噪技术 一.前言 在现实生活和工作中,噪声无处不在,在许多领域中,如天文.医学图像和计算机视觉方面收集到的数据常常是含有噪声的.噪声可能来自获取数据的过程,也可能来自环境 ...