roger 发表于 2020-6-15 20:53:51

Linux Socket 开发代码整理

  这些代码来自于《传智播客C++全栈开发》系列课程,这里是在学习过程中整理下来的代码,以后用到的话方便直接查阅,这篇文章你可以随意转载无需添加任何处处。
Linux 多线程多进程相关  进程执行命令
#include <stdio.h>
#include <string.h>

int main()
{
FILE *fp = popen("ps -e | grep 'ps' | awk '{print $1}'","r");
char buffer= {0};

while(fgets(buffer,10,fp) != NULL)
{
printf("PID: %s \n",buffer);
}
pclose(fp);

return 0;
}
  getenv
#include <stdio.h>
#include <stdlib.h>

int main()
{

printf("%s",getenv("HOME"));
return 0;
}

  子进程:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
pid_t pid = fork();
if(pid < 0 )
{
exit(1);
}
if(pid == 0 )
{
// 子进程
printf("pid = %d --> ppid= %d \n",getpid(),getppid());

}else if(pid >0)
{
// 父进程的逻辑代码
printf("child pid = %d --> self= %d --> ppid=%d \n",pid,getpid(),getppid());
}

return 0;
}

  接着,我们如何让父进程创建5个子进程,如何实现。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
int work = 10;
pid_t pid =0;


for(int x =0;x<5;x++)
{
pid = fork();
if(pid == 0 )
{
// 开辟子进程
printf("ppid=%d --> pid = %d \n",getppid(),getpid());
break;   // 跳出子进程退出循环的接口
}else if(pid > 0)
{
printf("父进程 \n");
}
// sleep(x);
}
return 0;
}
  子进程回收: 阻塞等待,回收
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

int main()
{
pid_t pid = fork();

if(pid == 0)
{
printf("子进程 \n");
sleep(4);
}
else if(pid>0)
{
printf("父进程 \n");
pid_t wpid = wait(NULL);
printf("wit ok, wpid = %d pid = %d \n",wpid,pid);
while(1)
{
sleep(2);
}
}
return 0;
}
  withpid 回收
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>


int main()
{
pid_t pid = fork();

if(pid == 0)
{
printf("子进程 \n");
sleep(4);
}
else if(pid>0)
{
printf("父进程 \n");
int ret;

while(ret = waitpid(-1,NULL,WNOHANG)== 0)
{
sleep(1);
}
printf("ret = %d \n",ret);

while(1)
{
sleep(10);
}
}
return 0;
}
  what 实现多个子进程回收:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>


int main()
{
pid_t pid;
int thread = 0;

// 一次性创建是个线程
for(int thread=0;thread<10;thread++)
{
pid = fork();
if(pid == 0)
{
break;
}

sleep(thread);
// 循环回收子进程
if(thread == 10)
{
for(int x=0;x<10;x++)
{
wait(NULL);
}
}

}
return 0;
}

Linux 网络Socket编程基础  网络基础 socket
tcp_server
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <arpa/inet.h>
#include <ctype.h>

int main(int argc, const char* argv[])
{
    // 创建监听的套接字
    int lfd = socket(AF_INET, SOCK_STREAM, 0);
    if(lfd == -1)
    {
      perror("socket error");
      exit(1);
    }

    // lfd 和本地的IP port绑定
    struct sockaddr_in server;
    memset(&server, 0, sizeof(server));
    server.sin_family = AF_INET;    // 地址族协议 - ipv4
    server.sin_port = htons(8888);
    server.sin_addr.s_addr = htonl(INADDR_ANY);
    int ret = bind(lfd, (struct sockaddr*)&server, sizeof(server));
    if(ret == -1)
    {
      perror("bind error");
      exit(1);
    }

    // 设置监听
    ret = listen(lfd, 20);
    if(ret == -1)
    {
      perror("listen error");
      exit(1);
    }

    // 等待并接收连接请求
    struct sockaddr_in client;
    socklen_t len = sizeof(client);
    int cfd = accept(lfd, (struct sockaddr*)&client, &len);
    if(cfd == -1)
    {
      perror("accept error");
      exit(1);
    }

    printf(" accept successful !!!\n");
    char ipbuf = {0};
    printf("client IP: %s, port: %d\n",
         inet_ntop(AF_INET, &client.sin_addr.s_addr, ipbuf, sizeof(ipbuf)),
         ntohs(client.sin_port));
    // 一直通信
    while(1)
    {
      // 先接收数据
      char buf = {0};
      int len = read(cfd, buf, sizeof(buf));
      if(len == -1)
      {
            perror("read error");
            exit(1);
      }
      else if(len == 0)
      {
            printf(" 客户端已经断开了连接 \n");
            close(cfd);
            break;
      }
      else
      {
            printf("recv buf: %s\n", buf);
            // 转换 - 小写 - 大写
            for(int i=0; i<len; ++i)
            {
                buf = toupper(buf);
            }
            printf("send buf: %s\n", buf);
            write(cfd, buf, len);
      }
    }

    close(lfd);

    return 0;
}
  TCP 三次握手-并发
process_server.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <signal.h>
#include <sys/wait.h>
#include <errno.h>

// 进程回收函数
void recyle(int num)
{
    pid_t pid;
    while( (pid = waitpid(-1, NULL, WNOHANG)) > 0 )
    {
      printf("child died , pid = %d\n", pid);
    }
}

int main(int argc, const char* argv[])
{
    if(argc < 2)
    {
      printf("eg: ./a.out port\n");
      exit(1);
    }
    struct sockaddr_in serv_addr;
    socklen_t serv_len = sizeof(serv_addr);
    int port = atoi(argv);

    // 创建套接字
    int lfd = socket(AF_INET, SOCK_STREAM, 0);
    // 初始化服务器 sockaddr_in
    memset(&serv_addr, 0, serv_len);
    serv_addr.sin_family = AF_INET;                   // 地址族
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);    // 监听本机所有的IP
    serv_addr.sin_port = htons(port);            // 设置端口
    // 绑定IP和端口
    bind(lfd, (struct sockaddr*)&serv_addr, serv_len);

    // 设置同时监听的最大个数
    listen(lfd, 36);
    printf("Start accept ......\n");

    // 使用信号回收子进程pcb
    struct sigaction act;
    act.sa_handler = recyle;
    act.sa_flags = 0;
    sigemptyset(&act.sa_mask);
    sigaction(SIGCHLD, &act, NULL);

    struct sockaddr_in client_addr;
    socklen_t cli_len = sizeof(client_addr);
    while(1)
    {
      // 父进程接收连接请求
      // accept阻塞的时候被信号中断, 处理信号对应的操作之后
      // 回来之后不阻塞了, 直接返回-1, 这时候 errno==EINTR
      int cfd = accept(lfd, (struct sockaddr*)&client_addr, &cli_len);
      while(cfd == -1 && errno == EINTR)
      {
            cfd = accept(lfd, (struct sockaddr*)&client_addr, &cli_len);
      }
      printf("connect sucessful\n");
      // 创建子进程
      pid_t pid = fork();
      if(pid == 0)
      {
            close(lfd);
            // child process
            // 通信
            char ip;
            while(1)
            {
                // client ip port
                printf("client IP: %s, port: %d\n",
                     inet_ntop(AF_INET, &client_addr.sin_addr.s_addr, ip, sizeof(ip)),
                     ntohs(client_addr.sin_port));
                char buf;
                int len = read(cfd, buf, sizeof(buf));
                if(len == -1)
                {
                  perror("read error");
                  exit(1);
                }
                else if(len == 0)
                {
                  printf("客户端断开了连接\n");
                  close(cfd);
                  break;
                }
                else
                {
                  printf("recv buf: %s\n", buf);
                  write(cfd, buf, len);
                }
            }
            // 干掉子进程
            return 0;

      }
      else if(pid > 0)
      {
            // parent process
            close(cfd);
      }
    }

    close(lfd);
    return 0;
}
  pthread_server.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <pthread.h>

// 自定义数据结构
typedef struct SockInfo
{
    int fd; //
    struct sockaddr_in addr;
    pthread_t id;
}SockInfo;

// 子线程处理函数
void* worker(void* arg)
{
    char ip;
    char buf;
    SockInfo* info = (SockInfo*)arg;
    // 通信
    while(1)
    {
      printf("Client IP: %s, port: %d\n",
               inet_ntop(AF_INET, &info->addr.sin_addr.s_addr, ip, sizeof(ip)),
               ntohs(info->addr.sin_port));
      int len = read(info->fd, buf, sizeof(buf));
      if(len == -1)
      {
            perror("read error");
            pthread_exit(NULL);
      }
      else if(len == 0)
      {
            printf("客户端已经断开了连接\n");
            close(info->fd);
            break;
      }
      else
      {
            printf("recv buf: %s\n", buf);
            write(info->fd, buf, len);
      }
    }
    return NULL;
}

int main(int argc, const char* argv[])
{
    if(argc < 2)
    {
      printf("eg: ./a.out port\n");
      exit(1);
    }
    struct sockaddr_in serv_addr;
    socklen_t serv_len = sizeof(serv_addr);
    int port = atoi(argv);

    // 创建套接字
    int lfd = socket(AF_INET, SOCK_STREAM, 0);
    // 初始化服务器 sockaddr_in
    memset(&serv_addr, 0, serv_len);
    serv_addr.sin_family = AF_INET;                   // 地址族
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);    // 监听本机所有的IP
    serv_addr.sin_port = htons(port);            // 设置端口
    // 绑定IP和端口
    bind(lfd, (struct sockaddr*)&serv_addr, serv_len);

    // 设置同时监听的最大个数
    listen(lfd, 36);
    printf("Start accept ......\n");

    int i = 0;
    SockInfo info;
    // 规定 fd == -1
    for(i=0; i<sizeof(info)/sizeof(info); ++i)
    {
      info.fd = -1;
    }

    socklen_t cli_len = sizeof(struct sockaddr_in);
    while(1)
    {
      // 选一个没有被使用的, 最小的数组元素
      for(i=0; i<256; ++i)
      {
            if(info.fd == -1)
            {
                break;
            }
      }
      if(i == 256)
      {
            break;
      }
      // 主线程 - 等待接受连接请求
      info.fd = accept(lfd, (struct sockaddr*)&info.addr, &cli_len);

      // 创建子线程 - 通信
      pthread_create(&info.id, NULL, worker, &info);
      // 设置线程分离
      pthread_detach(info.id);

    }

    close(lfd);

    // 只退出主线程
    pthread_exit(NULL);
    return 0;
}
  tcp_client.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <arpa/inet.h>

int main(int argc, const char* argv[])
{
    if(argc < 2)
    {
      printf("eg: ./a.out port\n");
      exit(1);
    }

    int port = atoi(argv);
    // 创建套接字
    int fd = socket(AF_INET, SOCK_STREAM, 0);

    // 连接服务器
    struct sockaddr_in serv;
    memset(&serv, 0, sizeof(serv));
    serv.sin_family = AF_INET;
    serv.sin_port = htons(port);
    // oserv.sin_addr.s_addr = htonl();
    inet_pton(AF_INET, "127.0.0.1", &serv.sin_addr.s_addr);
    connect(fd, (struct sockaddr*)&serv, sizeof(serv) );

    // 通信
    while(1)
    {
      // 发送数据
      char buf;
      printf("请输入要发送的字符串: \n");
      fgets(buf, sizeof(buf), stdin);
      write(fd, buf, strlen(buf));

      // 等待接收数据
      int len = read(fd, buf, sizeof(buf));
      if(len == -1)
      {
            perror("read error");
            exit(1);
      }
      else if(len == 0)
      {
            printf("服务器端关闭了连接\n");
            break;
      }
      else
      {
            printf("recv buf: %s\n", buf);
      }
    }

    close(fd);
    return 0;
}
  wrap_socket
  server.c
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <strings.h>
#include <string.h>
#include <ctype.h>
#include <arpa/inet.h>

#include "wrap.h"

#define SERV_PORT 6666

int main(void)
{
    int sfd, cfd;
    int len, i;
    char buf, clie_IP;

    struct sockaddr_in serv_addr, clie_addr;
    socklen_t clie_addr_len;

    sfd = Socket(AF_INET, SOCK_STREAM, 0);

    bzero(&serv_addr, sizeof(serv_addr));         
    serv_addr.sin_family = AF_INET;               
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_addr.sin_port = htons(SERV_PORT);         

    Bind(sfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));

    Listen(sfd, 2);                              

    printf("wait for client connect ...\n");

    clie_addr_len = sizeof(clie_addr_len);
    cfd = Accept(sfd, (struct sockaddr *)&clie_addr, &clie_addr_len);
    printf("cfd = ----%d\n", cfd);

    printf("client IP: %sport:%d\n",
            inet_ntop(AF_INET, &clie_addr.sin_addr.s_addr, clie_IP, sizeof(clie_IP)),
            ntohs(clie_addr.sin_port));

    while (1)
    {
      len = Read(cfd, buf, sizeof(buf));
      Write(STDOUT_FILENO, buf, len);

      for (i = 0; i < len; i++)
            buf = toupper(buf);
      Write(cfd, buf, len);
    }

    Close(sfd);
    Close(cfd);

    return 0;
}
  client.c
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#include "wrap.h"

#define SERV_IP "127.0.0.1"
#define SERV_PORT 6666

int main(void)
{
    int sfd, len;
    struct sockaddr_in serv_addr;
    char buf;

    sfd = Socket(AF_INET, SOCK_STREAM, 0);

    bzero(&serv_addr, sizeof(serv_addr));                     
    serv_addr.sin_family = AF_INET;                           
    inet_pton(AF_INET, SERV_IP, &serv_addr.sin_addr.s_addr);   
    serv_addr.sin_port = htons(SERV_PORT);                     

    Connect(sfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));

    while (1) {
      fgets(buf, sizeof(buf), stdin);
      int r = Write(sfd, buf, strlen(buf));      
      printf("Write r ======== %d\n", r);
      len = Read(sfd, buf, sizeof(buf));
      printf("Read len ========= %d\n", len);
      Write(STDOUT_FILENO, buf, len);
    }

    Close(sfd);

    return 0;
}
  wrap.h wrap.c
#ifndef __WRAP_H_
#define __WRAP_H_

void perr_exit(const char *s);
int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr);
int Bind(int fd, const struct sockaddr *sa, socklen_t salen);
int Connect(int fd, const struct sockaddr *sa, socklen_t salen);
int Listen(int fd, int backlog);
int Socket(int family, int type, int protocol);
ssize_t Read(int fd, void *ptr, size_t nbytes);
ssize_t Write(int fd, const void *ptr, size_t nbytes);
int Close(int fd);
ssize_t Readn(int fd, void *vptr, size_t n);
ssize_t Writen(int fd, const void *vptr, size_t n);
ssize_t my_read(int fd, char *ptr);
ssize_t Readline(int fd, void *vptr, size_t maxlen);

#endif


#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>

void perr_exit(const char *s)
{
perror(s);
exit(-1);
}

int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr)
{
int n;

again:
if ((n = accept(fd, sa, salenptr)) < 0)
    {
      //ECONNABORTED 发生在重传(一定次数)失败后,强制关闭套接字
      //EINTR 进程被信号中断
if ((errno == ECONNABORTED) || (errno == EINTR))
      {
goto again;
      }
else
      {
perr_exit("accept error");
      }
}
return n;
}

int Bind(int fd, const struct sockaddr *sa, socklen_t salen)
{
    int n;

if ((n = bind(fd, sa, salen)) < 0)
    {
perr_exit("bind error");
    }

    return n;
}

int Connect(int fd, const struct sockaddr *sa, socklen_t salen)
{
    int n;
    n = connect(fd, sa, salen);
if (n < 0)
    {
perr_exit("connect error");
    }

    return n;
}

int Listen(int fd, int backlog)
{
    int n;

if ((n = listen(fd, backlog)) < 0)
    {
perr_exit("listen error");
    }

    return n;
}

int Socket(int family, int type, int protocol)
{
int n;

if ((n = socket(family, type, protocol)) < 0)
    {
perr_exit("socket error");
    }

return n;
}

ssize_t Read(int fd, void *ptr, size_t nbytes)
{
ssize_t n;

again:
if ( (n = read(fd, ptr, nbytes)) == -1)
    {
if (errno == EINTR)
goto again;
else
return -1;
}

return n;
}

ssize_t Write(int fd, const void *ptr, size_t nbytes)
{
ssize_t n;

again:
if ((n = write(fd, ptr, nbytes)) == -1)
    {
if (errno == EINTR)
goto again;
else
return -1;
}
return n;
}

int Close(int fd)
{
    int n;
if ((n = close(fd)) == -1)
perr_exit("close error");

    return n;
}

/*参三: 应该读取的字节数*/                        
//socket 4096readn(cfd, buf, 4096)   nleft = 4096-1500
ssize_t Readn(int fd, void *vptr, size_t n)
{
size_tnleft;            //usigned int 剩余未读取的字节数
ssize_t nread;            //int 实际读到的字节数
char   *ptr;

ptr = vptr;
nleft = n;                  //n 未读取字节数

while (nleft > 0)
    {
if ((nread = read(fd, ptr, nleft)) < 0)
      {
if (errno == EINTR)
            {
nread = 0;
            }
else
            {
return -1;
            }
}
      else if (nread == 0)
      {
break;
      }

nleft -= nread;   //nleft = nleft - nread
ptr += nread;
}
return n - nleft;
}

ssize_t Writen(int fd, const void *vptr, size_t n)
{
size_t nleft;
ssize_t nwritten;
const char *ptr;

ptr = vptr;
nleft = n;
while (nleft > 0)
    {
if ( (nwritten = write(fd, ptr, nleft)) <= 0)
      {
if (nwritten < 0 && errno == EINTR)
nwritten = 0;
else
return -1;
}
nleft -= nwritten;
ptr += nwritten;
}
return n;
}

static ssize_t my_read(int fd, char *ptr)
{
static int read_cnt;
static char *read_ptr;
static char read_buf;

if (read_cnt <= 0) {
again:
if ( (read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0)    //"hello\n"
      {
if (errno == EINTR)
goto again;
return -1;
}
      else if (read_cnt == 0)
return 0;

read_ptr = read_buf;
}
read_cnt--;
*ptr = *read_ptr++;

return 1;
}

/*readline --- fgets*/   
//传出参数 vptr
ssize_t Readline(int fd, void *vptr, size_t maxlen)
{
ssize_t n, rc;
char    c, *ptr;
ptr = vptr;

for (n = 1; n < maxlen; n++)
    {
if ((rc = my_read(fd, &c)) == 1)    //ptr[] = hello\n
      {
*ptr++ = c;
if (c == '\n')
break;
}
    else if (rc == 0)
    {
*ptr = 0;
return n-1;
}
      else
return -1;
}
*ptr = 0;

return n;
}
  mult_thread_concurrent
server.c
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <ctype.h>
#include <unistd.h>
#include <fcntl.h>

#include "wrap.h"

#define MAXLINE 8192
#define SERV_PORT 8000

struct s_info
{                     //定义一个结构体, 将地址结构跟cfd捆绑
    struct sockaddr_in cliaddr;
    int connfd;
};

void *do_work(void *arg)
{
    int n,i;
    struct s_info *ts = (struct s_info*)arg;
    char buf;
    char str;      //#define INET_ADDRSTRLEN 16可用"[+d"查看

    while (1)
    {
      n = Read(ts->connfd, buf, MAXLINE);                     //读客户端
      if (n == 0)
      {
            printf("the client %d closed...\n", ts->connfd);
            break;                                              //跳出循环,关闭cfd
      }
      printf("received from %s at PORT %d\n",
                inet_ntop(AF_INET, &(*ts).cliaddr.sin_addr, str, sizeof(str)),
                ntohs((*ts).cliaddr.sin_port));               //打印客户端信息(IP/PORT)

      for (i = 0; i < n; i++)
      {
            buf = toupper(buf);                           //小写-->大写
      }

      Write(STDOUT_FILENO, buf, n);                           //写出至屏幕
      Write(ts->connfd, buf, n);                              //回写给客户端
    }
    Close(ts->connfd);

    return NULL;
}

int main(void)
{
    struct sockaddr_in servaddr, cliaddr;
    socklen_t cliaddr_len;
    int listenfd, connfd;
    pthread_t tid;
    struct s_info ts;      //根据最大线程数创建结构体数组.
    int i = 0;

    listenfd = Socket(AF_INET, SOCK_STREAM, 0);                     //创建一个socket, 得到lfd

    bzero(&servaddr, sizeof(servaddr));                           //地址结构清零
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);                   //指定本地任意IP
    servaddr.sin_port = htons(SERV_PORT);                           //指定端口号 8000

    Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); //绑定

    Listen(listenfd, 128);      //设置同一时刻链接服务器上限数

    printf("Accepting client connect ...\n");

    while (1)
    {
      cliaddr_len = sizeof(cliaddr);
      connfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);   //阻塞监听客户端链接请求
      ts.cliaddr = cliaddr;
      ts.connfd = connfd;

      pthread_create(&tid, NULL, do_work, (void*)&ts);
      pthread_detach(tid);                                                    //子线程分离,防止僵线程产生.
      i++;
      if(i == 256)
      {
            break;
      }
    }

    return 0;
}
  client.c
/* client.c */
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "wrap.h"

#define MAXLINE 80
#define SERV_PORT 8000

int main(int argc, char *argv[])
{
struct sockaddr_in servaddr;
char buf;
int sockfd, n;

sockfd = Socket(AF_INET, SOCK_STREAM, 0);

bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr.s_addr);
servaddr.sin_port = htons(SERV_PORT);

Connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));

while (fgets(buf, MAXLINE, stdin) != NULL)
    {
Write(sockfd, buf, strlen(buf));
n = Read(sockfd, buf, MAXLINE);
if (n == 0)
printf("the other side has been closed.\n");
else
Write(STDOUT_FILENO, buf, n);
}

Close(sockfd);

return 0;
}
  wrap.h wrap.c
#ifndef __WRAP_H_
#define __WRAP_H_

void perr_exit(const char *s);
int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr);
int Bind(int fd, const struct sockaddr *sa, socklen_t salen);
int Connect(int fd, const struct sockaddr *sa, socklen_t salen);
int Listen(int fd, int backlog);
int Socket(int family, int type, int protocol);
ssize_t Read(int fd, void *ptr, size_t nbytes);
ssize_t Write(int fd, const void *ptr, size_t nbytes);
int Close(int fd);
ssize_t Readn(int fd, void *vptr, size_t n);
ssize_t Writen(int fd, const void *vptr, size_t n);
ssize_t my_read(int fd, char *ptr);
ssize_t Readline(int fd, void *vptr, size_t maxlen);

#endif


#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>

void perr_exit(const char *s)
{
perror(s);
exit(-1);
}

int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr)
{
int n;

again:
if ((n = accept(fd, sa, salenptr)) < 0) {
if ((errno == ECONNABORTED) || (errno == EINTR))
goto again;
else
perr_exit("accept error");
}
return n;
}

int Bind(int fd, const struct sockaddr *sa, socklen_t salen)
{
    int n;

if ((n = bind(fd, sa, salen)) < 0)
perr_exit("bind error");

    return n;
}

int Connect(int fd, const struct sockaddr *sa, socklen_t salen)
{
    int n;

if ((n = connect(fd, sa, salen)) < 0)
perr_exit("connect error");

    return n;
}

int Listen(int fd, int backlog)
{
    int n;

if ((n = listen(fd, backlog)) < 0)
perr_exit("listen error");

    return n;
}

int Socket(int family, int type, int protocol)
{
int n;

if ((n = socket(family, type, protocol)) < 0)
perr_exit("socket error");

return n;
}

ssize_t Read(int fd, void *ptr, size_t nbytes)
{
ssize_t n;

again:
if ( (n = read(fd, ptr, nbytes)) == -1) {
if (errno == EINTR)
goto again;
else
return -1;
}
return n;
}

ssize_t Write(int fd, const void *ptr, size_t nbytes)
{
ssize_t n;

again:
if ( (n = write(fd, ptr, nbytes)) == -1) {
if (errno == EINTR)
goto again;
else
return -1;
}
return n;
}

int Close(int fd)
{
    int n;
if ((n = close(fd)) == -1)
perr_exit("close error");

    return n;
}

/*参三: 应该读取的字节数*/
ssize_t Readn(int fd, void *vptr, size_t n)
{
size_tnleft;            //usigned int 剩余未读取的字节数
ssize_t nread;            //int 实际读到的字节数
char   *ptr;

ptr = vptr;
nleft = n;

while (nleft > 0) {
if ((nread = read(fd, ptr, nleft)) < 0) {
if (errno == EINTR)
nread = 0;
else
return -1;
} else if (nread == 0)
break;

nleft -= nread;
ptr += nread;
}
return n - nleft;
}

ssize_t Writen(int fd, const void *vptr, size_t n)
{
size_t nleft;
ssize_t nwritten;
const char *ptr;

ptr = vptr;
nleft = n;
while (nleft > 0) {
if ( (nwritten = write(fd, ptr, nleft)) <= 0) {
if (nwritten < 0 && errno == EINTR)
nwritten = 0;
else
return -1;
}

nleft -= nwritten;
ptr += nwritten;
}
return n;
}

static ssize_t my_read(int fd, char *ptr)
{
static int read_cnt;
static char *read_ptr;
static char read_buf;

if (read_cnt <= 0) {
again:
if ( (read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0) {
if (errno == EINTR)
goto again;
return -1;
} else if (read_cnt == 0)
return 0;
read_ptr = read_buf;
}
read_cnt--;
*ptr = *read_ptr++;

return 1;
}

ssize_t Readline(int fd, void *vptr, size_t maxlen)
{
ssize_t n, rc;
char    c, *ptr;

ptr = vptr;
for (n = 1; n < maxlen; n++) {
if ( (rc = my_read(fd, &c)) == 1) {
*ptr++ = c;
if (c== '\n')
break;
} else if (rc == 0) {
*ptr = 0;
return n - 1;
} else
return -1;
}
*ptr= 0;

return n;
}
  mult_process_concurrent
  client.c
/* client.c */
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "wrap.h"

#define MAXLINE 8192
#define SERV_PORT 8000

int main(int argc, char *argv[])
{
    struct sockaddr_in servaddr;
    char buf;
    int sockfd, n;

    sockfd = Socket(AF_INET, SOCK_STREAM, 0);

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
    servaddr.sin_port = htons(SERV_PORT);

    Connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));

    while (fgets(buf, MAXLINE, stdin) != NULL)
    {
      Write(sockfd, buf, strlen(buf));
      n = Read(sockfd, buf, MAXLINE);
      if (n == 0)
      {
            printf("the other side has been closed.\n");
            break;
      }
      else
            Write(STDOUT_FILENO, buf, n);
    }

    Close(sockfd);

    return 0;
}
  server.c
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/wait.h>
#include <ctype.h>
#include <unistd.h>

#include "wrap.h"

#define MAXLINE 8192
#define SERV_PORT 8000

void do_sigchild(int num)
{
    while (waitpid(0, NULL, WNOHANG) > 0);
}

int main(void)
{
    struct sockaddr_in servaddr, cliaddr;
    socklen_t cliaddr_len;
    int listenfd, connfd;
    char buf;
    char str;
    int i, n;
    pid_t pid;

    //临时屏蔽sigchld信号
    sigset_t myset;
    sigemptyset(&myset);
    sigaddset(&myset, SIGCHLD);
    // 自定义信号集 -》 内核阻塞信号集
    sigprocmask(SIG_BLOCK, &myset, NULL);


    listenfd = Socket(AF_INET, SOCK_STREAM, 0);

    int opt = 1;
    // 设置端口复用
    setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(SERV_PORT);

    Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));

    Listen(listenfd, 20);

    printf("Accepting connections ...\n");
    while (1)
    {
      cliaddr_len = sizeof(cliaddr);
      connfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);

      // 有新的连接则创建一个进程
      pid = fork();
      if (pid == 0)
      {
            Close(listenfd);
            while (1)
            {
                n = Read(connfd, buf, MAXLINE);
                if (n == 0)
                {
                  printf("the other side has been closed.\n");
                  break;
                }
                printf("received from %s at PORT %d\n",
                        inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
                        ntohs(cliaddr.sin_port));

                for (i = 0; i < n; i++)
                  buf = toupper(buf);

                Write(STDOUT_FILENO, buf, n);
                Write(connfd, buf, n);
            }
            Close(connfd);
            return 0;
      }
      else if (pid > 0)
      {
            struct sigaction act;
            act.sa_flags = 0;
            act.sa_handler = do_sigchild;
            sigemptyset(&act.sa_mask);
            sigaction(SIGCHLD, &act, NULL);
            // 解除对sigchld信号的屏蔽
            sigprocmask(SIG_UNBLOCK, &myset, NULL);

            Close(connfd);
      }
      else
      {
            perr_exit("fork");
      }
    }
    return 0;
}
  wrap.c wrap.h
#ifndef __WRAP_H_
#define __WRAP_H_

void perr_exit(const char *s);
int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr);
int Bind(int fd, const struct sockaddr *sa, socklen_t salen);
int Connect(int fd, const struct sockaddr *sa, socklen_t salen);
int Listen(int fd, int backlog);
int Socket(int family, int type, int protocol);
ssize_t Read(int fd, void *ptr, size_t nbytes);
ssize_t Write(int fd, const void *ptr, size_t nbytes);
int Close(int fd);
ssize_t Readn(int fd, void *vptr, size_t n);
ssize_t Writen(int fd, const void *vptr, size_t n);
ssize_t my_read(int fd, char *ptr);
ssize_t Readline(int fd, void *vptr, size_t maxlen);

#endif

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>

void perr_exit(const char *s)
{
perror(s);
exit(-1);
}

int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr)
{
int n;

again:
if ((n = accept(fd, sa, salenptr)) < 0) {
if ((errno == ECONNABORTED) || (errno == EINTR))
goto again;
else
perr_exit("accept error");
}
return n;
}

int Bind(int fd, const struct sockaddr *sa, socklen_t salen)
{
    int n;

if ((n = bind(fd, sa, salen)) < 0)
perr_exit("bind error");

    return n;
}

int Connect(int fd, const struct sockaddr *sa, socklen_t salen)
{
    int n;

if ((n = connect(fd, sa, salen)) < 0)
perr_exit("connect error");

    return n;
}

int Listen(int fd, int backlog)
{
    int n;

if ((n = listen(fd, backlog)) < 0)
perr_exit("listen error");

    return n;
}

int Socket(int family, int type, int protocol)
{
int n;

if ((n = socket(family, type, protocol)) < 0)
perr_exit("socket error");

return n;
}

ssize_t Read(int fd, void *ptr, size_t nbytes)
{
ssize_t n;

again:
if ( (n = read(fd, ptr, nbytes)) == -1) {
if (errno == EINTR)
goto again;
else
return -1;
}
return n;
}

ssize_t Write(int fd, const void *ptr, size_t nbytes)
{
ssize_t n;

again:
if ( (n = write(fd, ptr, nbytes)) == -1) {
if (errno == EINTR)
goto again;
else
return -1;
}
return n;
}

int Close(int fd)
{
    int n;
if ((n = close(fd)) == -1)
perr_exit("close error");

    return n;
}

/*参三: 应该读取的字节数*/
ssize_t Readn(int fd, void *vptr, size_t n)
{
size_tnleft;            //usigned int 剩余未读取的字节数
ssize_t nread;            //int 实际读到的字节数
char   *ptr;

ptr = vptr;
nleft = n;

while (nleft > 0) {
if ((nread = read(fd, ptr, nleft)) < 0) {
if (errno == EINTR)
nread = 0;
else
return -1;
} else if (nread == 0)
break;

nleft -= nread;
ptr += nread;
}
return n - nleft;
}

ssize_t Writen(int fd, const void *vptr, size_t n)
{
size_t nleft;
ssize_t nwritten;
const char *ptr;

ptr = vptr;
nleft = n;
while (nleft > 0) {
if ( (nwritten = write(fd, ptr, nleft)) <= 0) {
if (nwritten < 0 && errno == EINTR)
nwritten = 0;
else
return -1;
}

nleft -= nwritten;
ptr += nwritten;
}
return n;
}

static ssize_t my_read(int fd, char *ptr)
{
static int read_cnt;
static char *read_ptr;
static char read_buf;

if (read_cnt <= 0) {
again:
if ( (read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0) {
if (errno == EINTR)
goto again;
return -1;
} else if (read_cnt == 0)
return 0;
read_ptr = read_buf;
}
read_cnt--;
*ptr = *read_ptr++;

return 1;
}

ssize_t Readline(int fd, void *vptr, size_t maxlen)
{
ssize_t n, rc;
char    c, *ptr;

ptr = vptr;
for (n = 1; n < maxlen; n++) {
if ( (rc = my_read(fd, &c)) == 1) {
*ptr++ = c;
if (c== '\n')
break;
} else if (rc == 0) {
*ptr = 0;
return n - 1;
} else
return -1;
}
*ptr= 0;

return n;
}
  tcp/client server
client.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <arpa/inet.h>


int main(int argc, const char* argv[])
{
    // 创建一个通信的套接字
    int fd = socket(AF_INET, SOCK_STREAM, 0);
    if(fd == -1)
    {
      perror("socket error");
      exit(1);
    }

    // 连接服务器
    struct sockaddr_in serv_addr;
    bzero(&serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(9999);
    inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr.s_addr);

    int ret = connect(fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
    if(ret == -1)
    {
      perror("connect error");
      exit(1);
    }

    // 通信
    while(1)
    {
      // 从终端读一个字符串
      char buf = {0};
      fgets(buf, sizeof(buf), stdin);
      // 发数据
      write(fd, buf, strlen(buf)+1);

      // 接收
      // 阻塞等待
      int len = read(fd, buf, sizeof(buf));
      if(len == -1)
      {
            perror("read error");
            exit(1);
      }
      printf("read buf = %s\n", buf);
      
    }

    close(fd);

    return 0;
}
  server.c
#include <stdio.h>
#include <ctype.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>

// server
int main(int argc, const char* argv[])
{
    // 创建监听的套接字
    int lfd = socket(AF_INET, SOCK_STREAM, 0);
    if(lfd == -1)
    {
      perror("socket error");
      exit(1);
    }

    // 绑定
    struct sockaddr_in serv_addr;
    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(9999);
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);// 本地多有的IP
    // 127.0.0.1
    // inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr.s_addr);
   
    // 设置端口复用
    // 需要在bind函数之前设置
    int opt = 1;
//    setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, (void*)&opt, sizeof(opt));

    // 绑定端口
    int ret = bind(lfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
    if(ret == -1)
    {
      perror("bind error");
      exit(1);
    }

    // 监听
    ret = listen(lfd, 64);
    if(ret == -1)
    {
      perror("listen error");
      exit(1);
    }

    // 阻塞等待连接请求, 并接受连接请求
    struct sockaddr_in clien_addr;
    socklen_t clien_len = sizeof(clien_addr);
    int cfd = accept(lfd, (struct sockaddr*)&clien_addr, &clien_len);
    if(cfd == -1)
    {
      perror("accetp error");
      exit(1);
    }

    char ipbuf;
    printf("client iP: %s, port: %d\n", inet_ntop(AF_INET, &clien_addr.sin_addr.s_addr, ipbuf, sizeof(ipbuf)),
         ntohs(clien_addr.sin_port));

    char buf = {0};
    while(1)
    {
      // read data
      // int len = read(cfd, buf, sizeof(buf));
      int len = recv(cfd, buf, sizeof(buf), 0);
      if(len == -1)
      {
            perror("recv error");
            exit(1);
      }
      else if(len == 0)
      {
            printf("客户端已经断开连接。。。\n");
            break;
      }
      printf("read buf = %s\n", buf);
      // 小写转大写
      for(int i=0; i<len; ++i)
      {
            buf = toupper(buf);
      }
      printf("after buf = %s\n", buf);

      // 大写串发给客户端
      // write(cfd, buf, strlen(buf)+1);
      ret = send(cfd, buf, strlen(buf)+1, 0);
      if(ret == -1)
      {
            perror("send error");
            exit(1);
      }
    }

    close(cfd);
    close(lfd);

    return 0;

}
  select
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <sys/select.h>

#define SERV_PORT 8989

int main(int argc, const char* argv[])
{
    int lfd, cfd;
    struct sockaddr_in serv_addr, clien_addr;
    int serv_len, clien_len;

    // 创建套接字
    lfd = socket(AF_INET, SOCK_STREAM, 0);
    // 初始化服务器 sockaddr_in
    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;                   // 地址族
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);    // 监听本机所有的IP
    serv_addr.sin_port = htons(SERV_PORT);            // 设置端口
    serv_len = sizeof(serv_addr);
    // 绑定IP和端口
    bind(lfd, (struct sockaddr*)&serv_addr, serv_len);

    // 设置同时监听的最大个数
    listen(lfd, 36);
    printf("Start accept ......\n");

    int ret;
    int maxfd = lfd;
    // reads 实时更新,temps 内核检测
    fd_set reads, temps;

    FD_ZERO(&reads);
    FD_SET(lfd, &reads);

    while(1)
    {
      temps = reads;
      ret = select(maxfd+1, &temps, NULL, NULL, NULL);
      if(ret == -1)
      {
            perror("select error");
            exit(1);
      }


      // 判断是否有新连接
      if(FD_ISSET(lfd, &temps))
      {
            // 接受连接请求
            clien_len = sizeof(clien_len);
            int cfd = accept(lfd, (struct sockaddr*)&clien_addr, &clien_len);

            // 文件描述符放入检测集合
            FD_SET(cfd, &reads);
            // 更新最大文件描述符
            maxfd = maxfd < cfd ? cfd : maxfd;
      }

      // 遍历检测的文件描述符是否有读操作
      for(int i=lfd+1; i<=maxfd; ++i)
      {
            if(FD_ISSET(i, &temps))
            {
                // 读数据
                char buf = {0};
                int len = read(i, buf, sizeof(buf));
                if(len== -1)
                {
                  perror("read error");
                  exit(1);
                }
                else if(len == 0)
                {
                  // 对方关闭了连接
                  FD_CLR(i, &reads);
                  close(i);
                  if(maxfd == i)
                  {
                        maxfd--;
                  }
                }
                else
                {
                  printf("read buf = %s\n", buf);
                  for(int j=0; j<len; ++j)
                  {
                        buf = toupper(buf);
                  }
                  printf("--buf toupper: %s\n", buf);
                  write(i, buf, strlen(buf)+1);
                }
            }
      }
    }

    close(lfd);
    return 0;
}
  select-plush.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <sys/select.h>

#define SERV_PORT 8989

int main(int argc, const char* argv[])
{
    int lfd, cfd;
    struct sockaddr_in serv_addr, clien_addr;
    int serv_len, clien_len;

    // 创建套接字
    lfd = socket(AF_INET, SOCK_STREAM, 0);
    // 初始化服务器 sockaddr_in
    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;                   // 地址族
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);    // 监听本机所有的IP
    serv_addr.sin_port = htons(SERV_PORT);            // 设置端口
    serv_len = sizeof(serv_addr);
    // 绑定IP和端口
    bind(lfd, (struct sockaddr*)&serv_addr, serv_len);

    // 设置同时监听的最大个数
    listen(lfd, 36);
    printf("Start accept ......\n");

    int ret;
    int maxfd = lfd;
    // reads 实时更新,temps 内核检测
    fd_set reads, temps;
   
    /*===============================================================*/
    // 记录要检测的文件描述符的数组
    int allfd;   // 1024
    // 记录数组中最后一个元素的下标
    int last_index = 0;
    // 初始化数组
    for(int i=0; i<FD_SETSIZE; ++i)
    {
      allfd = -1;// 无效文件描述符值
    }
    allfd = lfd;   // 监听的文件描述符添加到数组中
    /*===============================================================*/

    // 初始化监听的读集合
    FD_ZERO(&reads);
    FD_SET(lfd, &reads);

    while(1)
    {
      // 每次都需要更新,否则select不会重新检测
      temps = reads;
      ret = select(maxfd+1, &temps, NULL, NULL, NULL);
      if(ret == -1)
      {
            perror("select error");
            exit(1);
      }

      int i = 0;
      char bufip;
      // 判断是否有新连接
      if(FD_ISSET(lfd, &temps))
      {
            // 接受连接请求
            clien_len = sizeof(clien_len);
            int cfd = accept(lfd, (struct sockaddr*)&clien_addr, &clien_len);
            printf("client ip: %s, port: %d\n",
                   inet_ntop(AF_INET, &clien_addr.sin_addr.s_addr, bufip, sizeof(bufip)),
                   ntohs(clien_addr.sin_port));

            // 文件描述符放入检测集合
            FD_SET(cfd, &reads);
            // 更新最大文件描述符
            maxfd = maxfd < cfd ? cfd : maxfd;
            // cfd添加到检测数组中
            for(i=0; i<FD_SETSIZE; ++i)
            {
                if(allfd == -1)
                {
                  allfd = cfd;
                  break;
                }
            }
            // 更新数组最后一个有效值下标
            last_index = last_index < i ? i : last_index;
      }

      // 遍历检测的文件描述符是否有读操作
      for(i=lfd+1; i<=maxfd; ++i)
      {
            if(FD_ISSET(i, &temps))
            {
                // 读数据
                char buf = {0};
                int len = read(i, buf, sizeof(buf));
                if(len== -1)
                {
                  perror("read error");
                  exit(1);
                }
                else if(len == 0)
                {
                  // 对方关闭了连接
                  FD_CLR(i, &reads);
                  close(i);
                  if(maxfd == i)
                  {
                        maxfd--;
                  }
                  allfd = -1;
                  printf("对方已经关闭了连接。。。。。。\n");
                }
                else
                {
                  printf("read buf = %s\n", buf);
                  for(int j=0; j<len; ++j)
                  {
                        buf = toupper(buf);
                  }
                  printf("--buf toupper: %s\n", buf);
                  write(i, buf, strlen(buf)+1);
                }
            }
      }
    }

    close(lfd);
    return 0;
}
  pool
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <poll.h>

#define SERV_PORT 8989

int main(int argc, const char* argv[])
{
    int lfd, cfd;
    struct sockaddr_in serv_addr, clien_addr;
    int serv_len, clien_len;

    // 创建套接字
    lfd = socket(AF_INET, SOCK_STREAM, 0);
    // 初始化服务器 sockaddr_in
    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;                   // 地址族
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);    // 监听本机所有的IP
    serv_addr.sin_port = htons(SERV_PORT);            // 设置端口
    serv_len = sizeof(serv_addr);
    // 绑定IP和端口
    bind(lfd, (struct sockaddr*)&serv_addr, serv_len);

    // 设置同时监听的最大个数
    listen(lfd, 36);
    printf("Start accept ......\n");

    // poll结构体
    struct pollfd allfd;
    int max_index = 0;
    // init
    for(int i=0; i<1024; ++i)
    {
      allfd.fd = -1;
    }
    allfd.fd = lfd;
allfd.events = POLLIN;

    while(1)
    {
      int i = 0;
      int ret = poll(allfd, max_index+1, -1);
      if(ret == -1)
      {
            perror("poll error");
            exit(1);
      }

      // 判断是否有连接请求
      if(allfd.revents & POLLIN)
      {
            clien_len = sizeof(clien_addr);
            // 接受连接请求
            int cfd = accept(lfd, (struct sockaddr*)&clien_addr, &clien_len);
            printf("============\n");

            // cfd添加到poll数组
            for(i=0; i<1024; ++i)
            {
                if(allfd.fd == -1)
                {
                  allfd.fd = cfd;
                  break;
                }
            }
            // 更新最后一个元素的下标
            max_index = max_index < i ? i : max_index;
      }

      // 遍历数组
      for(i=1; i<=max_index; ++i)
      {
            int fd = allfd.fd;
            if(fd == -1)
            {
                continue;
            }
            if(allfd.revents & POLLIN)
            {
                // 接受数据
                char buf = {0};
                int len = recv(fd, buf, sizeof(buf), 0);
                if(len == -1)
                {
                  perror("recv error");
                  exit(1);
                }
                else if(len == 0)
                {
                  allfd.fd = -1;
                  close(fd);
                  printf("客户端已经主动断开连接。。。\n");
                }
                else
                {
                  printf("recv buf = %s\n", buf);
                  for(int k=0; k<len; ++k)
                  {
                        buf = toupper(buf);
                  }
                  printf("buf toupper: %s\n", buf);
                  send(fd, buf, strlen(buf)+1, 0);
                }

            }

      }
    }

    close(lfd);
    return 0;
}
  epool
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <sys/epoll.h>


int main(int argc, const char* argv[])
{
    if(argc < 2)
    {
      printf("eg: ./a.out port\n");
      exit(1);
    }
    struct sockaddr_in serv_addr;
    socklen_t serv_len = sizeof(serv_addr);
    int port = atoi(argv);

    // 创建套接字
    int lfd = socket(AF_INET, SOCK_STREAM, 0);
    // 初始化服务器 sockaddr_in
    memset(&serv_addr, 0, serv_len);
    serv_addr.sin_family = AF_INET;                   // 地址族
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);    // 监听本机所有的IP
    serv_addr.sin_port = htons(port);            // 设置端口
    // 绑定IP和端口
    bind(lfd, (struct sockaddr*)&serv_addr, serv_len);

    // 设置同时监听的最大个数
    listen(lfd, 36);
    printf("Start accept ......\n");

    struct sockaddr_in client_addr;
    socklen_t cli_len = sizeof(client_addr);

    // 创建epoll树根节点
    int epfd = epoll_create(2000);
    // 初始化epoll树
    struct epoll_event ev;
    ev.events = EPOLLIN;
    ev.data.fd = lfd;
    epoll_ctl(epfd, EPOLL_CTL_ADD, lfd, &ev);

    struct epoll_event all;
    while(1)
    {
      // 使用epoll通知内核fd 文件IO检测
      int ret = epoll_wait(epfd, all, sizeof(all)/sizeof(all), -1);

      // 遍历all数组中的前ret个元素
      for(int i=0; i<ret; ++i)
      {
            int fd = all.data.fd;
            // 判断是否有新连接
            if(fd == lfd)
            {
                // 接受连接请求
                int cfd = accept(lfd, (struct sockaddr*)&client_addr, &cli_len);
                if(cfd == -1)
                {
                  perror("accept error");
                  exit(1);
                }
                // 将新得到的cfd挂到树上
                struct epoll_event temp;
                temp.events = EPOLLIN;
                temp.data.fd = cfd;
                epoll_ctl(epfd, EPOLL_CTL_ADD, cfd, &temp);
               
                // 打印客户端信息
                char ip = {0};
                printf("New Client IP: %s, Port: %d\n",
                  inet_ntop(AF_INET, &client_addr.sin_addr.s_addr, ip, sizeof(ip)),
                  ntohs(client_addr.sin_port));
               
            }
            else
            {
                // 处理已经连接的客户端发送过来的数据
                if(!all.events & EPOLLIN)
                {
                  continue;
                }

                // 读数据
                char buf = {0};
                int len = recv(fd, buf, sizeof(buf), 0);
                if(len == -1)
                {
                  perror("recv error");
                  exit(1);
                }
                else if(len == 0)
                {
                  printf("client disconnected ....\n");
                  close(fd);
                  // fd从epoll树上删除
                  epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);
                }
                else
                {
                  printf(" recv buf: %s\n", buf);
                  write(fd, buf, len);
                }
            }
      }
    }

    close(lfd);
    return 0;
}
  epool-plus
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <sys/epoll.h>

typedef struct sockinfo
{
    int fd;
    struct sockaddr_in sock;
}SockInfo;

int main(int argc, const char* argv[])
{
    if(argc < 2)
    {
      printf("./a.out port\n");
      exit(1);
    }
    int lfd, cfd;
    struct sockaddr_in serv_addr, clien_addr;
    int serv_len, clien_len;
    int port = atoi(argv);

    // 创建套接字
    lfd = socket(AF_INET, SOCK_STREAM, 0);
    // 初始化服务器 sockaddr_in
    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;                   // 地址族
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);    // 监听本机所有的IP
    serv_addr.sin_port = htons(port);            // 设置端口
    serv_len = sizeof(serv_addr);
    // 绑定IP和端口
    bind(lfd, (struct sockaddr*)&serv_addr, serv_len);

    // 设置同时监听的最大个数
    listen(lfd, 36);
    printf("Start accept ......\n");

    // 创建红黑树根节点
    int epfd = epoll_create(2000);
    if(epfd == -1)
    {
      perror("epoll_create error");
      exit(1);
    }
    // lfd添加到监听列表
    SockInfo* sinfo = (SockInfo*)malloc(sizeof(SockInfo));
    sinfo->sock = serv_addr;
    sinfo->fd = lfd;
    struct epoll_event ev;
    ev.data.ptr = sinfo;
    ev.events = EPOLLIN;
    int ret = epoll_ctl(epfd, EPOLL_CTL_ADD, lfd, &ev);
    if(ret == -1)
    {
      perror("epoll_ctl error");
      exit(1);
    }

    struct epoll_event res;
    while(1)
    {            
      // 设置监听
      ret = epoll_wait(epfd, res, sizeof(res)/sizeof(res), -1);
      if(ret == -1)
      {
            perror("epoll_wait error");
            exit(1);
      }

      // 遍历前ret个元素
      for(int i=0; i<ret; ++i)
      {
            int fd = ((SockInfo*)res.data.ptr)->fd;
            if(res.events != EPOLLIN)
            {
                continue;
            }
            // 判断文件描述符是否为lfd
            if(fd == lfd)
            {
                char ipbuf;
                SockInfo *info = (SockInfo*)malloc(sizeof(SockInfo));
                clien_len = sizeof(clien_addr);
                cfd = accept(lfd, (struct sockaddr*)&clien_addr, &clien_len);
                // cfd 添加到监听树
                info->fd = cfd;
                info->sock = clien_addr;
                struct epoll_event ev;
                ev.events = EPOLLIN;
                ev.data.ptr = (void*)info;
                epoll_ctl(epfd, EPOLL_CTL_ADD, cfd, &ev);
                printf("client connected, fd = %d, IP = %s, Port = %d\n", cfd,
                     inet_ntop(AF_INET, &clien_addr.sin_addr.s_addr, ipbuf, sizeof(ipbuf)),
                     ntohs(clien_addr.sin_port));
            }
            else
            {
                // 通信
                char ipbuf;
                char buf = {0};
                int len = recv(fd, buf, sizeof(buf), 0);
                SockInfo* p = (SockInfo*)res.data.ptr;
                if(len == -1)
                {
                  perror("recv error");
                  exit(1);
                }
                else if(len == 0)
                {
                  // ip
                  inet_ntop(AF_INET, &p->sock.sin_addr.s_addr, ipbuf, sizeof(ipbuf));
                  printf("client %d 已经断开连接, Ip = %s, Port = %d\n",
                           fd, ipbuf, ntohs(p->sock.sin_port));
                  // 节点从树上删除
                  epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);
                  close(fd);
                  free(p);
                }
                else
                {
                  printf("Recv data from client %d, Ip = %s, Port = %d\n",
                           fd, ipbuf, ntohs(p->sock.sin_port));
                  printf("    === buf = %s\n", buf);
                  send(fd, buf, strlen(buf)+1, 0);
                }
            }
      }
    }

    close(lfd);
    free(sinfo);
    return 0;
}
  epool-client-server
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <arpa/inet.h>

int main(int argc, const char* argv[])
{
    // create socket
    int fd = socket(AF_INET, SOCK_DGRAM, 0);
    if(fd == -1)
    {
      perror("socket error");
      exit(1);
    }

    // 初始化服务器的IP和端口
    struct sockaddr_in serv;
    memset(&serv, 0, sizeof(serv));
    serv.sin_family = AF_INET;
    serv.sin_port = htons(8765);
    inet_pton(AF_INET, "127.0.0.1", &serv.sin_addr.s_addr);

    // 通信
    while(1)
    {
      char buf = {0};
      fgets(buf, sizeof(buf), stdin);
      // 数据的发送 - server - IP port
      sendto(fd, buf, strlen(buf)+1, 0, (struct sockaddr*)&serv, sizeof(serv));

      // 等待服务器发送数据过来
      recvfrom(fd, buf, sizeof(buf), 0, NULL, NULL);
      printf("recv buf: %s\n", buf);
    }
   
    close(fd);

    return 0;
}

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <arpa/inet.h>

int main(int argc, const char* argv[])
{
    // 创建套接字
    int fd = socket(AF_INET, SOCK_DGRAM, 0);
    if(fd == -1)
    {
      perror("socket error");
      exit(1);
    }
   
    // fd绑定本地的IP和端口
    struct sockaddr_in serv;
    memset(&serv, 0, sizeof(serv));
    serv.sin_family = AF_INET;
    serv.sin_port = htons(8765);
    serv.sin_addr.s_addr = htonl(INADDR_ANY);
    int ret = bind(fd, (struct sockaddr*)&serv, sizeof(serv));
    if(ret == -1)
    {
      perror("bind error");
      exit(1);
    }

    struct sockaddr_in client;
    socklen_t cli_len = sizeof(client);
    // 通信
    char buf = {0};
    while(1)
    {
      int recvlen = recvfrom(fd, buf, sizeof(buf), 0,
                               (struct sockaddr*)&client, &cli_len);
      if(recvlen == -1)
      {
            perror("recvform error");
            exit(1);
      }
      
      printf("recv buf: %s\n", buf);
      char ip = {0};
      printf("New Client IP: %s, Port: %d\n",
            inet_ntop(AF_INET, &client.sin_addr.s_addr, ip, sizeof(ip)),
            ntohs(client.sin_port));

      // 给客户端发送数据
      sendto(fd, buf, strlen(buf)+1, 0, (struct sockaddr*)&client, sizeof(client));
    }
   
    close(fd);

    return 0;
}
  广播通信
client.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <arpa/inet.h>

int main(int argc, const char* argv[])
{
    int fd = socket(AF_INET, SOCK_DGRAM, 0);
    if(fd == -1)
    {
      perror("socket error");
      exit(1);
    }

    // 绑定iP和端口
    struct sockaddr_in client;
    memset(&client, 0, sizeof(client));
    client.sin_family = AF_INET;
    client.sin_port = htons(6767);
    inet_pton(AF_INET, "0.0.0.0", &client.sin_addr.s_addr);
    int ret= bind(fd, (struct sockaddr*)&client, sizeof(client));
    if(ret == -1)
    {
      perror("bind error");
      exit(1);
    }

    // 接收数据
    while(1)
    {
      char buf = {0};
      int len = recvfrom(fd, buf, sizeof(buf), 0, NULL, NULL);
      if(len == -1)
      {
            perror("recvfrom error");
            break;
      }
      
      printf("client == recv buf: %s\n", buf);
    }

    close(fd);
   
    return 0;
}
  server.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <arpa/inet.h>

int main(int argc, const char* argv[])
{
    // 创建套接字
    int fd = socket(AF_INET, SOCK_DGRAM, 0);
    if(fd == -1)
    {
      perror("socket error");
      exit(1);
    }

    // 绑定server的iP和端口
    struct sockaddr_in serv;
    memset(&serv, 0, sizeof(serv));
    serv.sin_family= AF_INET;
    serv.sin_port = htons(8787);    // server端口
    serv.sin_addr.s_addr = htonl(INADDR_ANY);
    int ret = bind(fd, (struct sockaddr*)&serv, sizeof(serv));
    if(ret == -1)
    {
      perror("bind error");
      exit(1);
    }

    // 初始化客户端地址信息
    struct sockaddr_in client;
    memset(&client, 0, sizeof(client));
    client.sin_family = AF_INET;
    client.sin_port = htons(6767);// 客户端要绑定的端口
    // 使用广播地址给客户端发数据
    inet_pton(AF_INET, "192.168.123.255", &client.sin_addr.s_addr);

    // 给服务器开放广播权限
    int flag = 1;
    setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &flag, sizeof(flag));

    // 通信
    while(1)
    {
      // 一直给客户端发数据
      static int num = 0;
      char buf = {0};
      sprintf(buf, "hello, udp == %d\n", num++);
      int ret = sendto(fd, buf, strlen(buf)+1, 0, (struct sockaddr*)&client, sizeof(client));
      if(ret == -1)
      {
            perror("sendto error");
            break;
      }
      
      printf("server == send buf: %s\n", buf);

      sleep(1);
    }
   
    close(fd);

    return 0;
}
  localIPC广播
client.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/un.h>

int main(int argc, const char* argv[])
{
    int fd = socket(AF_LOCAL, SOCK_STREAM, 0);
    if(fd == -1)
    {
      perror("socket error");
      exit(1);
    }

    unlink("client.sock");

    // ================================
    // 给客户端绑定一个套接字文件
    struct sockaddr_un client;
    client.sun_family = AF_LOCAL;
    strcpy(client.sun_path, "client.sock");
    int ret = bind(fd, (struct sockaddr*)&client, sizeof(client));
    if(ret == -1)
    {
      perror("bind error");
      exit(1);
    }

    // 初始化server信息
    struct sockaddr_un serv;
    serv.sun_family = AF_LOCAL;
    strcpy(serv.sun_path, "server.sock");

    // 连接服务器
    connect(fd, (struct sockaddr*)&serv, sizeof(serv));

    // 通信
    while(1)
    {
      char buf = {0};
      fgets(buf, sizeof(buf), stdin);
      send(fd, buf, strlen(buf)+1, 0);

      // 接收数据
      recv(fd, buf, sizeof(buf), 0);
      printf("recv buf: %s\n", buf);
    }

    close(fd);

    return 0;
}
  server.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/un.h>

int main(int argc, const char* argv[])
{
    int lfd = socket(AF_LOCAL, SOCK_STREAM, 0);
    if(lfd == -1)
    {
      perror("socket error");
      exit(1);
    }

    // 如果套接字文件存在, 删除套接字文件
    unlink("server.sock");

    // 绑定
    struct sockaddr_un serv;
    serv.sun_family = AF_LOCAL;
    strcpy(serv.sun_path, "server.sock");
    int ret = bind(lfd, (struct sockaddr*)&serv, sizeof(serv));
    if(ret == -1)
    {
      perror("bind error");
      exit(1);
    }
   
    // 监听
    ret = listen(lfd, 36);
    if(ret == -1)
    {
      perror("listen error");
      exit(1);
    }

    // 等待接收连接请求
    struct sockaddr_un client;
    socklen_t len = sizeof(client);
    int cfd = accept(lfd, (struct sockaddr*)&client, &len);
    if(cfd == -1)
    {
      perror("accept error");
      exit(1);
    }
    printf("======client bind file: %s\n", client.sun_path);
   
    // 通信
    while(1)
    {
      char buf = {0};
      int recvlen = recv(cfd, buf, sizeof(buf), 0);
      if(recvlen == -1)
      {
            perror("recv error");
            exit(1);
      }
      else if(recvlen == 0)
      {
            printf("clietn disconnect ....\n");
            close(cfd);
            break;
      }
      else
      {
            printf("recv buf: %s\n", buf);
            send(cfd, buf, recvlen, 0);
      }
    }
    close(cfd);
    close(lfd);
   
    return 0;
}
  multicast广播
client.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <arpa/inet.h>
#include <net/if.h>

int main(int argc, const char* argv[])
{
    int fd = socket(AF_INET, SOCK_DGRAM, 0);
    if(fd == -1)
    {
      perror("socket error");
      exit(1);
    }

    // 绑定iP和端口
    struct sockaddr_in client;
    memset(&client, 0, sizeof(client));
    client.sin_family = AF_INET;
    client.sin_port = htons(6767); // ........
    inet_pton(AF_INET, "0.0.0.0", &client.sin_addr.s_addr);
    int ret= bind(fd, (struct sockaddr*)&client, sizeof(client));
    if(ret == -1)
    {
      perror("bind error");
      exit(1);
    }

    // 加入到组播地址
    struct ip_mreqn fl;
    inet_pton(AF_INET, "239.0.0.10", &fl.imr_multiaddr.s_addr);
    inet_pton(AF_INET, "0.0.0.0", &fl.imr_address.s_addr);
    fl.imr_ifindex = if_nametoindex("ens33");
    setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &fl, sizeof(fl));

    // 接收数据
    while(1)
    {
      char buf = {0};
      int len = recvfrom(fd, buf, sizeof(buf), 0, NULL, NULL);
      if(len == -1)
      {
            perror("recvfrom error");
            break;
      }
      
      printf("client == recv buf: %s\n", buf);
    }

    close(fd);
   
    return 0;
}
  server.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <arpa/inet.h>
#include <net/if.h>

int main(int argc, const char* argv[])
{
    // 创建套接字
    int fd = socket(AF_INET, SOCK_DGRAM, 0);
    if(fd == -1)
    {
      perror("socket error");
      exit(1);
    }

    // 绑定server的iP和端口
    struct sockaddr_in serv;
    memset(&serv, 0, sizeof(serv));
    serv.sin_family= AF_INET;
    serv.sin_port = htons(8787);    // server端口
    serv.sin_addr.s_addr = htonl(INADDR_ANY);
    int ret = bind(fd, (struct sockaddr*)&serv, sizeof(serv));
    if(ret == -1)
    {
      perror("bind error");
      exit(1);
    }

    // 初始化客户端地址信息
    struct sockaddr_in client;
    memset(&client, 0, sizeof(client));
    client.sin_family = AF_INET;
    client.sin_port = htons(6767);// 客户端要绑定的端口
    // 使用组播地址给客户端发数据
    inet_pton(AF_INET, "239.0.0.10", &client.sin_addr.s_addr);

    // 给服务器开放组播权限
    struct ip_mreqn flag;
    // init flag
    inet_pton(AF_INET, "239.0.0.10", &flag.imr_multiaddr.s_addr);   // 组播地址
    inet_pton(AF_INET, "0.0.0.0", &flag.imr_address.s_addr);    // 本地IP
    flag.imr_ifindex = if_nametoindex("ens33");
    setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, &flag, sizeof(flag));

    // 通信
    while(1)
    {
      // 一直给客户端发数据
      static int num = 0;
      char buf = {0};
      sprintf(buf, "hello, udp == %d\n", num++);
      int ret = sendto(fd, buf, strlen(buf)+1, 0, (struct sockaddr*)&client, sizeof(client));
      if(ret == -1)
      {
            perror("sendto error");
            break;
      }
      
      printf("server == send buf: %s\n", buf);

      sleep(1);
    }
   
    close(fd);

    return 0;
}

Libevent 高并发库  libevent event*
read_fifo.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>
#include <event2/event.h>

// 对操作处理函数
void read_cb(evutil_socket_t fd, short what, void *arg)
{
    // 读管道
    char buf = {0};
    int len = read(fd, buf, sizeof(buf));
    printf("data len = %d, buf = %s\n", len, buf);
    printf("read event: %s", what & EV_READ ? "Yes" : "No");
}


// 读管道
int main(int argc, const char* argv[])
{
    unlink("myfifo");
    //创建有名管道
    mkfifo("myfifo", 0664);

    // open file
    int fd = open("myfifo", O_RDONLY | O_NONBLOCK);
    if(fd == -1)
    {
      perror("open error");
      exit(1);
    }

    // 读管道
    struct event_base* base = NULL;
    base = event_base_new();

    // 创建事件
    struct event* ev = NULL;
    ev = event_new(base, fd, EV_READ | EV_PERSIST, read_cb, NULL);

    // 添加事件
    event_add(ev, NULL);

    // 事件循环
    event_base_dispatch(base);

    // 释放资源
    event_free(ev);
    event_base_free(base);
    close(fd);
   
    return 0;
}
  write_fifo.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>
#include <event2/event.h>

// 对操作处理函数
void write_cb(evutil_socket_t fd, short what, void *arg)
{
    // write管道
    char buf = {0};
    static int num = 0;
    sprintf(buf, "hello, world == %d\n", num++);
    write(fd, buf, strlen(buf)+1);
}


// 写管道
int main(int argc, const char* argv[])
{
    // open file
    int fd = open("myfifo", O_WRONLY | O_NONBLOCK);
    if(fd == -1)
    {
      perror("open error");
      exit(1);
    }

    // 写管道
    struct event_base* base = NULL;
    base = event_base_new();

    // 创建事件
    struct event* ev = NULL;
    // 检测的写缓冲区是否有空间写
    ev = event_new(base, fd, EV_WRITE , write_cb, NULL);

    // 添加事件
    event_add(ev, NULL);

    // 事件循环
    event_base_dispatch(base);

    // 释放资源
    event_free(ev);
    event_base_free(base);
    close(fd);
   
    return 0;
}
  libevent- buffer event
client.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <event2/event.h>
#include <event2/bufferevent.h>


void read_cb(struct bufferevent *bev, void *arg)
{
    char buf = {0};
    bufferevent_read(bev, buf, sizeof(buf));
    printf("Server say: %s\n", buf);
}

void write_cb(struct bufferevent *bev, void *arg)
{
    printf("I am Write_cb function....\n");
}

void event_cb(struct bufferevent *bev, short events, void *arg)
{
    if (events & BEV_EVENT_EOF)
    {
      printf("connection closed\n");
    }
    else if(events & BEV_EVENT_ERROR)   
    {
      printf("some other error\n");
    }
    else if(events & BEV_EVENT_CONNECTED)
    {
      printf("成功连接到服务器, O(∩_∩)O哈哈~\n");
      return;
    }
   
    bufferevent_free(bev);
    printf("free bufferevent...\n");
}

void send_cb(evutil_socket_t fd, short what, void *arg)
{
    char buf = {0};
    struct bufferevent* bev = (struct bufferevent*)arg;
    printf("请输入要发送的数据: \n");
    read(fd, buf, sizeof(buf));
    bufferevent_write(bev, buf, strlen(buf)+1);
}


int main(int argc, const char* argv[])
{
    struct event_base* base;
    base = event_base_new();


    struct bufferevent* bev;
    bev = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE);

    // 连接服务器
    struct sockaddr_in serv;
    memset(&serv, 0, sizeof(serv));
    serv.sin_family = AF_INET;
    serv.sin_port = htons(9876);
    evutil_inet_pton(AF_INET, "127.0.0.1", &serv.sin_addr.s_addr);
    bufferevent_socket_connect(bev, (struct sockaddr*)&serv, sizeof(serv));

    // 设置回调
    bufferevent_setcb(bev, read_cb, write_cb, event_cb, NULL);
    bufferevent_enable(bev, EV_READ | EV_PERSIST);

    // 创建一个事件
    struct event* ev = event_new(base, STDIN_FILENO,
                                 EV_READ | EV_PERSIST,
                                 send_cb, bev);
    event_add(ev, NULL);
   
    event_base_dispatch(base);

    event_base_free(base);

    return 0;
}
  server.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <event2/event.h>
#include <event2/listener.h>
#include <event2/bufferevent.h>

// 读缓冲区回调
void read_cb(struct bufferevent *bev, void *arg)
{
    char buf = {0};   
    bufferevent_read(bev, buf, sizeof(buf));
    char* p = "我已经收到了你发送的数据!";
    printf("client say: %s\n", p);

    // 发数据给客户端
    bufferevent_write(bev, p, strlen(p)+1);
    printf("====== send buf: %s\n", p);
}

// 写缓冲区回调
void write_cb(struct bufferevent *bev, void *arg)
{
    printf("我是写缓冲区的回调函数...\n");
}

// 事件
void event_cb(struct bufferevent *bev, short events, void *arg)
{
    if (events & BEV_EVENT_EOF)
    {
      printf("connection closed\n");
    }
    else if(events & BEV_EVENT_ERROR)   
    {
      printf("some other error\n");
    }
   
    bufferevent_free(bev);   
    printf("buffevent 资源已经被释放...\n");
}



void cb_listener(
      struct evconnlistener *listener,
      evutil_socket_t fd,
      struct sockaddr *addr,
      int len, void *ptr)
{
   printf("connect new client\n");

   struct event_base* base = (struct event_base*)ptr;
   // 通信操作
   // 添加新事件
   struct bufferevent *bev;
   bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);

   // 给bufferevent缓冲区设置回调
   bufferevent_setcb(bev, read_cb, write_cb, event_cb, NULL);
   bufferevent_enable(bev, EV_READ);
}


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

    // init server
    struct sockaddr_in serv;
    memset(&serv, 0, sizeof(serv));
    serv.sin_family = AF_INET;
    serv.sin_port = htons(9876);
    serv.sin_addr.s_addr = htonl(INADDR_ANY);

    struct event_base* base;
    base = event_base_new();
    // 创建套接字
    // 绑定
    // 接收连接请求
    struct evconnlistener* listener;
    listener = evconnlistener_new_bind(base, cb_listener, base,
                                  LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE,
                                  36, (struct sockaddr*)&serv, sizeof(serv));

    event_base_dispatch(base);

    evconnlistener_free(listener);
    event_base_free(base);

    return 0;
}
  libevent
client.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>
#include <event2/event.h>

void cb_write(evutil_socket_t fd, short what, void* arg)
{
    printf("what = %d\n", what);
    while(1)
    {
      static int num = 0;
      char buf = {0};
      sprintf(buf, "hello world, %d\n", num++);
      write(fd, buf, strlen(buf)+1);
      sleep(1);
    }
}

int main(int argc, const char* argv[])
{
    int fd = open("myfifo", O_WRONLY);
    if(fd == -1)
    {
      perror("open error");
      exit(1);
    }

    struct event_base *base = event_base_new();
    struct event* ev = event_new(base, fd, EV_WRITE | EV_PERSIST,
                                 cb_write, "this is write callback func!");
    event_add(ev, NULL);

    event_base_dispatch(base);

    event_free(ev);
    event_base_free(base);

    close(fd);
   
    return 0;
}
  server.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <event2/event.h>
#include <event2/listener.h>
#include <event2/bufferevent.h>

// 读缓冲区回调
void read_cb(struct bufferevent *bev, void *arg)
{
    char buf = {0};   
    bufferevent_read(bev, buf, sizeof(buf));
    char* p = "我已经收到了你发送的数据!";
    printf("client say: %s\n", p);

    // 发数据给客户端
    bufferevent_write(bev, p, strlen(p)+1);
    printf("====== send buf: %s\n", p);
}

// 写缓冲区回调
void write_cb(struct bufferevent *bev, void *arg)
{
    printf("我是写缓冲区的回调函数...\n");
}

// 事件
void event_cb(struct bufferevent *bev, short events, void *arg)
{
    if (events & BEV_EVENT_EOF)
    {
      printf("connection closed\n");
    }
    else if(events & BEV_EVENT_ERROR)   
    {
      printf("some other error\n");
    }
   
    bufferevent_free(bev);   
    printf("buffevent 资源已经被释放...\n");
}



void cb_listener(
      struct evconnlistener *listener,
      evutil_socket_t fd,
      struct sockaddr *addr,
      int len, void *ptr)
{
   printf("connect new client\n");

   struct event_base* base = (struct event_base*)ptr;
   // 通信操作
   // 添加新事件
   struct bufferevent *bev;
   bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);

   // 给bufferevent缓冲区设置回调
   bufferevent_setcb(bev, read_cb, write_cb, event_cb, NULL);
   bufferevent_enable(bev, EV_READ);
}


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

    // init server
    struct sockaddr_in serv;
    memset(&serv, 0, sizeof(serv));
    serv.sin_family = AF_INET;
    serv.sin_port = htons(9876);
    serv.sin_addr.s_addr = htonl(INADDR_ANY);

    struct event_base* base;
    base = event_base_new();
    // 创建套接字
    // 绑定
    // 接收连接请求
    struct evconnlistener* listener;
    listener = evconnlistener_new_bind(base, cb_listener, base,
                                  LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE,
                                  36, (struct sockaddr*)&serv, sizeof(serv));

    event_base_dispatch(base);

    evconnlistener_free(listener);
    event_base_free(base);

    return 0;
}

Web 服务器开发  process_server.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <signal.h>
#include <sys/wait.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>

// 进程回收函数
void recyle(int num)
{
    pid_t pid;
    while( (pid = waitpid(-1, NULL, WNOHANG)) > 0 )
    {
      printf("child died , pid = %d\n", pid);
    }
}

void get_request_line_args(char* msg, char* method, char* path, char* protocol)
{
    int i = 0;
    char* p = msg;
    while(*p != ' ')
    {
      method = *p++;

    }
    p++;
    method = 0;
    i = 0;
    while(*p != ' ')
    {
      path = *p++;

    }

    p++;
    path = 0;
    i = 0;
    while(*p != '\r' && *(p+1) != '\n')
    {
      protocol = *p;
      p++;

    }
    protocol = 0;

}

void send_respond_head(int cfd, int size)
{
    char buf = {0};
    sprintf(buf, "http/1.1 200 OK\r\n");
    write(cfd, buf, strlen(buf));

    sprintf(buf, "Content-Type: text/plain\r\n");
    write(cfd, buf, strlen(buf));
    sprintf(buf, "Content-Length: %d\r\n", size);
    write(cfd, buf, strlen(buf));

    // 空行
    write(cfd, "\r\n", 2);
}

int main(int argc, const char* argv[])
{
    if(argc < 2)
    {
      printf("eg: ./a.out port\n");
      exit(1);
    }

    // 切换当前进程到资源目录
    chdir(argv);

    struct sockaddr_in serv_addr;
    socklen_t serv_len = sizeof(serv_addr);
    int port = atoi(argv);

    // 创建套接字
    int lfd = socket(AF_INET, SOCK_STREAM, 0);
    // 初始化服务器 sockaddr_in
    memset(&serv_addr, 0, serv_len);
    serv_addr.sin_family = AF_INET;                   // 地址族
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);    // 监听本机所有的IP
    serv_addr.sin_port = htons(port);            // 设置端口
    // 绑定IP和端口
    int fl = 1;
    setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &fl, sizeof(fl));
    bind(lfd, (struct sockaddr*)&serv_addr, serv_len);

    // 设置同时监听的最大个数
    listen(lfd, 36);
    printf("Start accept ......\n");

    // 使用信号回收子进程pcb
    struct sigaction act;
    act.sa_handler = recyle;
    act.sa_flags = 0;
    sigemptyset(&act.sa_mask);
    sigaction(SIGCHLD, &act, NULL);

    struct sockaddr_in client_addr;
    socklen_t cli_len = sizeof(client_addr);
    while(1)
    {
      // 父进程接收连接请求
      // accept阻塞的时候被信号中断, 处理信号对应的操作之后
      // 回来之后不阻塞了, 直接返回-1, 这时候 errno==EINTR
      int cfd = accept(lfd, (struct sockaddr*)&client_addr, &cli_len);
      while(cfd == -1 && errno == EINTR)
      {
            cfd = accept(lfd, (struct sockaddr*)&client_addr, &cli_len);
      }
      printf("connect sucessful\n");
      // 创建子进程
      pid_t pid = fork();
      if(pid == 0)
      {
            close(lfd);
            // child process
            // 通信
            char ip;
                // client ip port
                printf("client IP: %s, port: %d\n",
                     inet_ntop(AF_INET, &client_addr.sin_addr.s_addr, ip, sizeof(ip)),
                     ntohs(client_addr.sin_port));
                char buf;
                int len = read(cfd, buf, sizeof(buf));
                if(len == -1)
                {
                  perror("read error");
                  exit(1);
                }
                else if(len == 0)
                {
                  printf("客户端断开了连接\n");
                  close(cfd);
                  break;
                }
                else
                {
                  char method, path, protocol;
                  get_request_line_args(buf, method, path, protocol);
                  printf("method = %s, path = %s, protocol = %s\n",
                           method, path, protocol);

                  // 得到文件名
                  char* file = path+1;
                  printf("============file = %s\n", file);
                  // 获取文件属性
                  struct stat st;
                  int ret = stat(file, &st);
                  if(ret == -1)
                  {
                        perror("stat error");
                        exit(1);
                  }
                  // 打开文件
                  int fdd = open(file, O_RDONLY);
                  // 发送响应头
                  send_respond_head(cfd, (int)st.st_size);
                  // 读文件
                  while( (len = read(fdd, buf, sizeof(buf))) > 0 )
                  {
                        //发送数据给浏览器
                        write(cfd, buf, len);
                        write(STDOUT_FILENO, buf, len);
                  }
                }
            // 干掉子进程
            return 0;

      }
      else if(pid > 0)
      {
            // parent process
            close(cfd);
      }
    }

    close(lfd);
    return 0;
}
  epool 实现的web服务器
epool_server.h
#ifndef _EPOLL_SERVER_H
#define _EPOLL_SERVER_H

int init_listen_fd(int port, int epfd);
void epoll_run(int port);
void do_accept(int lfd, int epfd);
void do_read(int cfd, int epfd);
int get_line(int sock, char *buf, int size);
void disconnect(int cfd, int epfd);
void http_request(const char* request, int cfd);
void send_respond_head(int cfd, int no, const char* desp, const char* type, long len);
void send_file(int cfd, const char* filename);
void send_dir(int cfd, const char* dirname);
void encode_str(char* to, int tosize, const char* from);
void decode_str(char *to, char *from);
const char *get_file_type(const char *name);

#endif
  epool_server.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <sys/epoll.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <dirent.h>
#include <sys/stat.h>
#include <ctype.h>
#include "epoll_server.h"

#define MAXSIZE 2000

void epoll_run(int port)
{
    // 创建一个epoll树的根节点
    int epfd = epoll_create(MAXSIZE);
    if(epfd == -1)
    {
      perror("epoll_create error");
      exit(1);
    }

    // 添加要监听的节点
    // 先添加监听lfd
    int lfd = init_listen_fd(port, epfd);

    // 委托内核检测添加到树上的节点
    struct epoll_event all;
    while(1)
    {
      int ret = epoll_wait(epfd, all, MAXSIZE, -1);
      if(ret == -1)
      {
            perror("epoll_wait error");
            exit(1);
      }

      // 遍历发生变化的节点
      for(int i=0; i<ret; ++i)
      {
            // 只处理读事件, 其他事件默认不处理
            struct epoll_event *pev = &all;
            if(!(pev->events & EPOLLIN))
            {
                // 不是读事件
                continue;
            }

            if(pev->data.fd == lfd)
            {
                // 接受连接请求
                do_accept(lfd, epfd);
            }
            else
            {
                // 读数据
                do_read(pev->data.fd, epfd);
            }
      }
    }
}

// 读数据
void do_read(int cfd, int epfd)
{
    // 将浏览器发过来的数据, 读到buf中
    char line = {0};
    // 读请求行
    int len = get_line(cfd, line, sizeof(line));
    if(len == 0)
    {
      printf("客户端断开了连接...\n");
      // 关闭套接字, cfd从epoll上del
      disconnect(cfd, epfd);         
    }
    else
    {
      printf("请求行数据: %s", line);
      printf("============= 请求头 ============\n");
      // 还有数据没读完
      // 继续读
      while(len)
      {
            char buf = {0};
            len = get_line(cfd, buf, sizeof(buf));
            printf("-----: %s", buf);
      }
      printf("============= The End ============\n");
    }

    // 请求行: get /xxx http/1.1
    // 判断是不是get请求
    if(strncasecmp("get", line, 3) == 0)
    {
      // 处理http请求
      http_request(line, cfd);
      // 关闭套接字, cfd从epoll上del
      disconnect(cfd, epfd);         
    }
}

// 断开连接的函数
void disconnect(int cfd, int epfd)
{
    int ret = epoll_ctl(epfd, EPOLL_CTL_DEL, cfd, NULL);
    if(ret == -1)
    {
      perror("epoll_ctl del cfd error");
      exit(1);
    }
    close(cfd);
}

// http请求处理
void http_request(const char* request, int cfd)
{
    // 拆分http请求行
    // get /xxx http/1.1
    char method, path, protocol;
    sscanf(request, "%[^ ] %[^ ] %[^ ]", method, path, protocol);

    printf("method = %s, path = %s, protocol = %s\n", method, path, protocol);

    // 转码 将不能识别的中文乱码 - > 中文
    // 解码 %23 %34 %5f
    decode_str(path, path);
      // 处理path/xx
      // 去掉path中的/
      char* file = path+1;
    // 如果没有指定访问的资源, 默认显示资源目录中的内容
    if(strcmp(path, "/") == 0)
    {
      // file的值, 资源目录的当前位置
      file = "./";
    }

    // 获取文件属性
    struct stat st;
    int ret = stat(file, &st);
    if(ret == -1)
    {
      // show 404
      send_respond_head(cfd, 404, "File Not Found", ".html", -1);
      send_file(cfd, "404.html");
    }

    // 判断是目录还是文件
    // 如果是目录
    if(S_ISDIR(st.st_mode))
    {
      // 发送头信息
      send_respond_head(cfd, 200, "OK", get_file_type(".html"), -1);
      // 发送目录信息
      send_dir(cfd, file);
    }
    else if(S_ISREG(st.st_mode))
    {
      // 文件
      // 发送消息报头
      send_respond_head(cfd, 200, "OK", get_file_type(file), st.st_size);
      // 发送文件内容
      send_file(cfd, file);
    }
}

// 发送目录内容
void send_dir(int cfd, const char* dirname)
{
    // 拼一个html页面<table></table>
    char buf = {0};

    sprintf(buf, "<html><head><title>目录名: %s</title></head>", dirname);
    sprintf(buf+strlen(buf), "<body><h1>当前目录: %s</h1><table>", dirname);

    char enstr = {0};
    char path = {0};
    // 目录项二级指针
    struct dirent** ptr;
    int num = scandir(dirname, &ptr, NULL, alphasort);
    // 遍历
    for(int i=0; i<num; ++i)
    {
      char* name = ptr->d_name;

      // 拼接文件的完整路径
      sprintf(path, "%s/%s", dirname, name);
      printf("path = %s ===================\n", path);
      struct stat st;
      stat(path, &st);

      encode_str(enstr, sizeof(enstr), name);
      // 如果是文件
      if(S_ISREG(st.st_mode))
      {
            sprintf(buf+strlen(buf),
                  "<tr><td><a href=\"%s\">%s</a></td><td>%ld</td></tr>",
                  enstr, name, (long)st.st_size);
      }
      // 如果是目录
      else if(S_ISDIR(st.st_mode))
      {
            sprintf(buf+strlen(buf),
                  "<tr><td><a href=\"%s/\">%s/</a></td><td>%ld</td></tr>",
                  enstr, name, (long)st.st_size);
      }
      send(cfd, buf, strlen(buf), 0);
      memset(buf, 0, sizeof(buf));
      // 字符串拼接
    }

    sprintf(buf+strlen(buf), "</table></body></html>");
    send(cfd, buf, strlen(buf), 0);

    printf("dir message send OK!!!!\n");
#if 0
    // 打开目录
    DIR* dir = opendir(dirname);
    if(dir == NULL)
    {
      perror("opendir error");
      exit(1);
    }

    // 读目录
    struct dirent* ptr = NULL;
    while( (ptr = readdir(dir)) != NULL )
    {
      char* name = ptr->d_name;
    }
    closedir(dir);
#endif
}

// 发送响应头
void send_respond_head(int cfd, int no, const char* desp, const char* type, long len)
{
    char buf = {0};
    // 状态行
    sprintf(buf, "http/1.1 %d %s\r\n", no, desp);
    send(cfd, buf, strlen(buf), 0);
    // 消息报头
    sprintf(buf, "Content-Type:%s\r\n", type);
    sprintf(buf+strlen(buf), "Content-Length:%ld\r\n", len);
    send(cfd, buf, strlen(buf), 0);
    // 空行
    send(cfd, "\r\n", 2, 0);
}

// 发送文件
void send_file(int cfd, const char* filename)
{
    // 打开文件
    int fd = open(filename, O_RDONLY);
    if(fd == -1)
    {
      // show 404
      return;
    }

    // 循环读文件
    char buf = {0};
    int len = 0;
    while( (len = read(fd, buf, sizeof(buf))) > 0 )
    {
      // 发送读出的数据
      send(cfd, buf, len, 0);
    }
    if(len == -1)
    {
      perror("read file error");
      exit(1);
    }

    close(fd);
}

// 解析http请求消息的每一行内容
int get_line(int sock, char *buf, int size)
{
    int i = 0;
    char c = '\0';
    int n;
    while ((i < size - 1) && (c != '\n'))
    {
      n = recv(sock, &c, 1, 0);
      if (n > 0)
      {
            if (c == '\r')
            {
                n = recv(sock, &c, 1, MSG_PEEK);
                if ((n > 0) && (c == '\n'))
                {
                  recv(sock, &c, 1, 0);
                }
                else
                {
                  c = '\n';
                }
            }
            buf = c;
            i++;
      }
      else
      {
            c = '\n';
      }
    }
    buf = '\0';

    return i;
}

// 接受新连接处理
void do_accept(int lfd, int epfd)
{
    struct sockaddr_in client;
    socklen_t len = sizeof(client);
    int cfd = accept(lfd, (struct sockaddr*)&client, &len);
    if(cfd == -1)
    {
      perror("accept error");
      exit(1);
    }

    // 打印客户端信息
    char ip = {0};
    printf("New Client IP: %s, Port: %d, cfd = %d\n",
         inet_ntop(AF_INET, &client.sin_addr.s_addr, ip, sizeof(ip)),
         ntohs(client.sin_port), cfd);

    // 设置cfd为非阻塞
    int flag = fcntl(cfd, F_GETFL);
    flag |= O_NONBLOCK;
    fcntl(cfd, F_SETFL, flag);

    // 得到的新节点挂到epoll树上
    struct epoll_event ev;
    ev.data.fd = cfd;
    // 边沿非阻塞模式
    ev.events = EPOLLIN | EPOLLET;
    int ret = epoll_ctl(epfd, EPOLL_CTL_ADD, cfd, &ev);
    if(ret == -1)
    {
      perror("epoll_ctl add cfd error");
      exit(1);
    }
}

int init_listen_fd(int port, int epfd)
{
    // 创建监听的套接字
    int lfd = socket(AF_INET, SOCK_STREAM, 0);
    if(lfd == -1)
    {
      perror("socket error");
      exit(1);
    }

    // lfd绑定本地IP和port
    struct sockaddr_in serv;
    memset(&serv, 0, sizeof(serv));
    serv.sin_family = AF_INET;
    serv.sin_port = htons(port);
    serv.sin_addr.s_addr = htonl(INADDR_ANY);

    // 端口复用
    int flag = 1;
    setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag));
    int ret = bind(lfd, (struct sockaddr*)&serv, sizeof(serv));
    if(ret == -1)
    {
      perror("bind error");
      exit(1);
    }

    // 设置监听
    ret = listen(lfd, 64);
    if(ret == -1)
    {
      perror("listen error");
      exit(1);
    }

    // lfd添加到epoll树上
    struct epoll_event ev;
    ev.events = EPOLLIN;
    ev.data.fd = lfd;
    ret = epoll_ctl(epfd, EPOLL_CTL_ADD, lfd, &ev);
    if(ret == -1)
    {
      perror("epoll_ctl add lfd error");
      exit(1);
    }

    return lfd;
}

// 16进制数转化为10进制
int hexit(char c)
{
    if (c >= '0' && c <= '9')
      return c - '0';
    if (c >= 'a' && c <= 'f')
      return c - 'a' + 10;
    if (c >= 'A' && c <= 'F')
      return c - 'A' + 10;

    return 0;
}

/*
*这里的内容是处理%20之类的东西!是"解码"过程。
*%20 URL编码中的‘ ’(space)
*%21 '!' %22 '"' %23 '#' %24 '  new-httpSERVER
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/dir.h>

//#define SERVER_PORT 8888
#define FILE_404 "my404.html"
const char * workdir = "./";

typedef struct sockinfo
{
int fd;
struct sockaddr_in sock;
}SockInfo;

//http协议响应
void http_respond_head(int cfd, char * type, int size)
{
char buf = {0};

sprintf(buf, "http/1.1 200 OK\r\n");
send(cfd, buf, strlen(buf), MSG_NOSIGNAL);

sprintf(buf, "Content-Type: %s\r\n", type);
send(cfd, buf, strlen(buf), MSG_NOSIGNAL);
sprintf(buf, "Content-Length: %d\r\n", size);
send(cfd, buf, strlen(buf), MSG_NOSIGNAL);

send(cfd, "\r\n", 2, MSG_NOSIGNAL);
}

//404not_found

void not_found(int cfd)
{
struct stat st;
stat(FILE_404, &st);
http_respond_head(cfd, "text/html", (int)st.st_size);

int fd404 = open(FILE_404, O_RDONLY);
if(-1 == fd404)
{
perror("open err");
exit(1);
}
char buf = {0};
int len;
while((len=read(fd404,buf, sizeof(buf))) > 0)
{
write(cfd, buf, len);
}
if(0 == len)
{
close(fd404);
}
if(-1 == len)
{
perror("read err");
exit(1);
}
}




/**文件IO相关操作***/

//判断文件/目录 是否存在
int isExist(const char * path)
{
int ret = access(path, F_OK);
if(0 == ret)
{
return 1;
}
return 0;
}

//判断是否是目录
int isDir(const char * path)
{
struct stat st;
stat(path, &st);
return S_ISDIR(st.st_mode);
}



void showDir(const char * path)
{
char buf = {0};

int tempfd = open("temp.txt", O_WRONLY | O_CREAT|O_TRUNC, 0664);
if(-1 == tempfd)
{
perror("open temp.txt err");
exit(1);
}
sprintf(buf, "<font color=\"blue\" size=\"7\">当前路径:%s<br/></font>\n", path);
write(tempfd, buf, strlen(buf));

DIR * pdir;
struct dirent * pDirent;
pdir = opendir(path);
if(pdir)
{
while((pDirent = readdir(pdir)) != NULL)
{
if(strcmp(pDirent->d_name, ".") == 0)
{
continue;
}

if(strcmp(pDirent->d_name, "..") == 0)
{
continue;
}

char linkname = "http://192.168.18.133:8888/";

strcat(linkname, path + strlen(workdir));//跳过资源根路径
//printf("linkname=%s\n", linkname);
if(strcmp(path + strlen(workdir), ""))
{
strcat(linkname, "/");//path不是资源根目录,才需要加/
}
strcat(linkname, pDirent->d_name);
sprintf(buf, "<a href=\"%s\" target=\"_blank\">%s</a><br/>\n", linkname,pDirent->d_name);
write(tempfd, buf, strlen(buf));
}

}
else
{
printf("opendir err\n");
}
closedir(pdir);
close(tempfd);
}

int main(int argc, char * argv[])
{
//测试是否存在代码
//printf("%d\n", isExist("./rec"));



if(argc != 2)
{
printf("./a.out port\n");
exit(1);
}
int port = atoi(argv);
if(port < 100)
{
printf("port 号太小,请再次运行输入!\n");
exit(1);
}

//改变进程工作目录
//chdir("./rec");//进入资源目录


//创建套接字
int lfd = socket(AF_INET, SOCK_STREAM, 0);

//端口复用
int flag = 1;
setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag));
//绑定服务器IP 端口
struct sockaddr_in server;
memset(&server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(port);
server.sin_addr.s_addr = htonl(INADDR_ANY);
int ret = bind(lfd, (struct sockaddr*)&server, sizeof(server));
if(-1 == ret)
{
perror("bind err");
exit(1);
}

//设置同时监听的最大个数
listen(lfd, 66);
printf("start to accept ......\n");

//创建红黑树理论根节点个数
int epfd = epoll_create(2000);
if(-1 == epfd)
{
perror("epoll_create err");
exit(1);
}
//将lfd添加到监听列表
SockInfo * sinfo = (SockInfo*)malloc(sizeof(SockInfo));
sinfo->sock = server;//结构体直接赋值
sinfo->fd = lfd;

struct epoll_event ev;
ev.data.ptr = sinfo;
ev.events = EPOLLIN;
ret = epoll_ctl(epfd, EPOLL_CTL_ADD, lfd, &ev);
if(-1 == ret)
{
perror("epoll_ctl err");
exit(1);
}

struct epoll_event all;//存epoll_wait传出参数
//通信
while(1)
{
//设置监听-1一直阻塞,直到有事件才返回
int num = epoll_wait(epfd, all, sizeof(all) / sizeof(all), -1);
if(-1 == num)
{
perror("epoll_wait err");
exit(1);
}

//遍历前num个元素
int i;
for(i = 0; i < num; ++i)
{
//如果不是读事件,跳过本次循环
if(all.events != EPOLLIN)
{
continue;
}
int fd = ((SockInfo*)all.data.ptr)->fd;//拿到fd

//如果fd是监听lfd,说明有新的连接到来
if(fd == lfd)
{
char ipbuf;
SockInfo * info = (SockInfo *)malloc(sizeof(SockInfo));
struct sockaddr_in client;
socklen_t cli_len = sizeof(client);
int cfd = accept(lfd, (struct sockaddr*)&client, &cli_len);
if(-1 == cfd)
{
perror("accept err");
exit(1);
}
info->fd = cfd;
info->sock = client;//保存新连接的客户端的信息

struct epoll_event ev;
ev.events = EPOLLIN;
ev.data.ptr = info;//void * 指向 info

//挂到红黑树上
ret = epoll_ctl(epfd, EPOLL_CTL_ADD, cfd, &ev);
if(-1 == ret)
{
perror("epoll_ctl err");
exit(1);
}
printf("client connected, fd = %d, IP = %s, Port = %d\n",
cfd,
inet_ntop(AF_INET, &client.sin_addr.s_addr,ipbuf,sizeof(ipbuf)),
ntohs(client.sin_port));
}
else
{
//通信
char ipbuf;//用于通信的时候打印对应客户端的IP
char buf = {0};
SockInfo * p = (SockInfo *)all.data.ptr;//取出指向SockInfo结构体变量的指针
//拿到ip,后面用于显示哪个客户端
inet_ntop(AF_INET, &p->sock.sin_addr.s_addr, ipbuf, sizeof(ipbuf));

int len = recv(fd, buf, sizeof(buf), 0);
if(-1 == len)
{
perror("recv error");
exit(1);
}
else if(0 == len)
{
inet_ntop(AF_INET, &p->sock.sin_addr.s_addr, ipbuf, sizeof(ipbuf));
printf("client %d 已经断开连接, IP = %s, Port = %d\n",
fd,
ipbuf,
ntohs(p->sock.sin_port));
//从树上摘下节点
epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);
close(fd);//先摘下节点,才能关闭fd文件
if(p != NULL)
{
free(p);
p = NULL;
}
}
else
{

printf("浏览器请求:%s\n", buf);
//读数据
//先把buf中的请求行拿出来
char pathbuf = {0};//存浏览器请求的服务器路径
char path = {0};//存服务器中的实际路径
//path里面存着 /文件路径
sscanf(buf, "%*[^ ] %[^ ]", pathbuf);
//拼成服务器中的实际目录
sprintf(path, "%s%s", workdir, pathbuf + 1);

printf("path=%s\n", path);
//如果路径不存在,报404NOTFOUND
if(!isExist(path))
{
not_found(fd);
//close(fd);
continue;
}

//如果请求的是 资源根目录 或 资源根目录下的文件夹
if(isDir(path) || strcmp(pathbuf, "/") == 0)
{
//服务器根目录
if(strcmp(path, "/") == 0)
{
showDir("./");
}
else
{
showDir(path);
}
struct stat st;
stat("temp.txt", &st);
int tempfd = open("temp.txt", O_RDONLY);
if(-1 == tempfd)
{
printf("%s 打开错误!\n", path);
perror("open err");
exit(1);
}
http_respond_head(fd, "text/html", (int)st.st_size);
while((len = read(tempfd, buf, sizeof(buf))) > 0)
{
write(fd, buf, len);
}

close(tempfd);
}
else//不是目录
{
//找出来后缀
char * type = path + strlen(path);//type指向path结尾
while(type >= path)
{
if(*type == '.')
{
break;
}
--type;
}
//printf("type=%s\n", type);//打印后缀
char httptype = {0};
if(strcmp(type, ".html") == 0) strcpy(httptype, "text/html");
else if(strcmp(type, ".jpg") == 0) strcpy(httptype, "image/jpeg");
else if(strcmp(type, ".png") == 0) strcpy(httptype, "image/png");
else if(strcmp(type, ".mp3") == 0) strcpy(httptype, "audio/mpeg");
else if(strcmp(type, ".avi") == 0) strcpy(httptype, "video/x-msvideo");
else if(strcmp(type, ".mp4") == 0) strcpy(httptype, "video/mpeg");
else strcpy(httptype, "text/plain");//否则就当成普通文件


int rfd;
struct stat st;
int flag = 0;
/*if(strcmp(type, ".mp4") == 1)
{
flag = 1;
rfd = open("mymp4.html", O_RDONLY);
strcpy(httptype, "text/html");
//astruct stat st;
stat("mymp4.html", &st);

} */

{
rfd = open(path, O_RDONLY);

//struct stat st;
stat(path, &st);
}
if(-1 == rfd)
{
perror("open err");
exit(1);
}

printf("httptype=%s\n", httptype);
http_respond_head(fd, httptype, (int)st.st_size);
char bigbuf = {0};
printf("开始传%s\n", path);
while((len = read(rfd, bigbuf, sizeof(bigbuf)))>0)
{
//write(fd, bigbuf, len);
send(fd, bigbuf, len , MSG_NOSIGNAL);
}
close(rfd);

/*if(flag == 1)
{
stat(path, &st);
http_respond_head(fd, "text/plain", (int)st.st_size);
int rfd = open(path, O_RDONLY);
if(-1 == rfd)
{
perror("open err");
exit(1);
}

while((len = read(rfd, bigbuf, sizeof(bigbuf)))>0)
{
//write(fd, bigbuf, len);
send(fd, bigbuf, len , MSG_NOSIGNAL);
}
close(rfd);
}

*/

}

}

}
}
}

printf("服务器断开连接!\n");

close(lfd);
if(sinfo != NULL)
{
free(sinfo);
sinfo = NULL;
}
close(epfd);
return 0;
}
  libevent - 实现httpdServer
main.c
#include <stdio.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <event2/bufferevent.h>
#include <event2/listener.h>
#include <event2/event.h>
#include "libevent_http.h"

int main(int argc, char **argv)
{
    if(argc < 3)
    {
      printf("./event_http port path\n");
      return -1;
    }
    if(chdir(argv) < 0) {
      printf("dir is not exists: %s\n", argv);
      perror("chdir err:");
      return -1;
    }

    struct event_base *base;
    struct evconnlistener *listener;
    struct event *signal_event;

    struct sockaddr_in sin;
    base = event_base_new();
    if (!base)
    {
      fprintf(stderr, "Could not initialize libevent!\n");
      return 1;
    }

    memset(&sin, 0, sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_port = htons(atoi(argv));

    // 创建监听的套接字,绑定,监听,接受连接请求
    listener = evconnlistener_new_bind(base, listener_cb, (void *)base,
                  LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE, -1,
                  (struct sockaddr*)&sin, sizeof(sin));
    if (!listener)
    {
      fprintf(stderr, "Could not create a listener!\n");
      return 1;
    }

    // 创建信号事件, 捕捉并处理
    signal_event = evsignal_new(base, SIGINT, signal_cb, (void *)base);
    if (!signal_event || event_add(signal_event, NULL)<0)
    {
      fprintf(stderr, "Could not create/add a signal event!\n");
      return 1;
    }

    // 事件循环
    event_base_dispatch(base);

    evconnlistener_free(listener);
    event_free(signal_event);
    event_base_free(base);

    printf("done\n");

    return 0;
}
  libevent.h
#ifndef _LIBEVENT_HTTP_H
#define _LIBEVENT_HTTP_H

#include <event2/event.h>

void conn_eventcb(struct bufferevent *bev, short events, void *user_data);

void conn_readcb(struct bufferevent *bev, void *user_data);

const char *get_file_type(char *name);

int hexit(char c);

void listener_cb(struct evconnlistener *listener, evutil_socket_t fd,
               struct sockaddr *sa, int socklen, void *user_data);

int response_http(struct bufferevent *bev, const char *method, char *path);

int send_dir(struct bufferevent *bev,const char *dirname);

int send_error(struct bufferevent *bev);

int send_file_to_http(const char *filename, struct bufferevent *bev);

int send_header(struct bufferevent *bev, int no, const char* desp, const char *type, long len);

void signal_cb(evutil_socket_t sig, short events, void *user_data);

void strdecode(char *to, char *from);

void strencode(char* to, size_t tosize, const char* from);

#endif
  libevent.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include <string.h>
#include <dirent.h>
#include <time.h>
#include <signal.h>
#include <ctype.h>
#include <errno.h>
#include <event2/bufferevent.h>
#include <event2/buffer.h>
#include <event2/listener.h>
#include "libevent_http.h"

#define _HTTP_CLOSE_ "Connection: close\r\n"

int response_http(struct bufferevent *bev, const char *method, char *path)
{
    if(strcasecmp("GET", method) == 0){
      //get method ...
      strdecode(path, path);
      char *pf = &path;

      if(strcmp(path, "/") == 0 || strcmp(path, "/.") == 0)
      {
            pf="./";
      }

      printf("***** http Request Resource Path =%s, pf = %s\n", path, pf);

      struct stat sb;
      if(stat(pf,&sb) < 0)
      {
            perror("open file err:");
            send_error(bev);
            return -1;
      }

      if(S_ISDIR(sb.st_mode))//处理目录
      {
            //应该显示目录列表
            send_header(bev, 200, "OK", get_file_type(".html"), -1);
            send_dir(bev, pf);
      }
      else //处理文件
      {
            send_header(bev, 200, "OK", get_file_type(pf), sb.st_size);
            send_file_to_http(pf, bev);
      }
    }

    return 0;
}

/*
   *charset=iso-8859-1西欧的编码,说明网站采用的编码是英文;
   *charset=gb2312说明网站采用的编码是简体中文;
   *charset=utf-8代表世界通用的语言编码;
   *可以用到中文、韩文、日文等世界上所有语言编码上
   *charset=euc-kr说明网站采用的编码是韩文;
   *charset=big5说明网站采用的编码是繁体中文;
   *
   *以下是依据传递进来的文件名,使用后缀判断是何种文件类型
   *将对应的文件类型按照http定义的关键字发送回去
*/
const char *get_file_type(char *name)
{
    char* dot;

    dot = strrchr(name, '.');//自右向左查找‘.’字符;如不存在返回NULL

    if (dot == (char*)0)
      return "text/plain; charset=utf-8";
    if (strcmp(dot, ".html") == 0 || strcmp(dot, ".htm") == 0)
      return "text/html; charset=utf-8";
    if (strcmp(dot, ".jpg") == 0 || strcmp(dot, ".jpeg") == 0)
      return "image/jpeg";
    if (strcmp(dot, ".gif") == 0)
      return "image/gif";
    if (strcmp(dot, ".png") == 0)
      return "image/png";
    if (strcmp(dot, ".css") == 0)
      return "text/css";
    if (strcmp(dot, ".au") == 0)
      return "audio/basic";
    if (strcmp( dot, ".wav") == 0)
      return "audio/wav";
    if (strcmp(dot, ".avi") == 0)
      return "video/x-msvideo";
    if (strcmp(dot, ".mov") == 0 || strcmp(dot, ".qt") == 0)
      return "video/quicktime";
    if (strcmp(dot, ".mpeg") == 0 || strcmp(dot, ".mpe") == 0)
      return "video/mpeg";
    if (strcmp(dot, ".vrml") == 0 || strcmp(dot, ".wrl") == 0)
      return "model/vrml";
    if (strcmp(dot, ".midi") == 0 || strcmp(dot, ".mid") == 0)
      return "audio/midi";
    if (strcmp(dot, ".mp3") == 0)
      return "audio/mpeg";
    if (strcmp(dot, ".ogg") == 0)
      return "application/ogg";
    if (strcmp(dot, ".pac") == 0)
      return "application/x-ns-proxy-autoconfig";

    return "text/plain; charset=utf-8";
}

int send_file_to_http(const char *filename, struct bufferevent *bev)
{
    int fd = open(filename, O_RDONLY);
    int ret = 0;
    char buf = {0};

    while((ret = read(fd, buf, sizeof(buf)) ) )
    {
      bufferevent_write(bev, buf, ret);
      memset(buf, 0, ret);
    }
    close(fd);
    return 0;
}

int send_header(struct bufferevent *bev, int no, const char* desp, const char *type, long len)
{
    char buf={0};

    sprintf(buf, "HTTP/1.1 %d %s\r\n", no, desp);
    //HTTP/1.1 200 OK\r\n
    bufferevent_write(bev, buf, strlen(buf));
    // 文件类型
    sprintf(buf, "Content-Type:%s\r\n", type);
    bufferevent_write(bev, buf, strlen(buf));
    // 文件大小
    sprintf(buf, "Content-Length:%ld\r\n", len);
    bufferevent_write(bev, buf, strlen(buf));
    // Connection: close
    bufferevent_write(bev, _HTTP_CLOSE_, strlen(_HTTP_CLOSE_));
    //send \r\n
    bufferevent_write(bev, "\r\n", 2);

    return 0;
}

int send_error(struct bufferevent *bev)
{
    send_header(bev,404, "File Not Found", "text/html", -1);
    send_file_to_http("404.html", bev);
    return 0;
}

int send_dir(struct bufferevent *bev,const char *dirname)
{
    char encoded_name;
    char path;
    char timestr;
    struct stat sb;
    struct dirent **dirinfo;

    char buf = {0};
    sprintf(buf, "<html><head><meta charset=\"utf-8\"><title>%s</title></head>", dirname);
    sprintf(buf+strlen(buf), "<body><h1>当前目录:%s</h1><table>", dirname);
    //添加目录内容
    int num = scandir(dirname, &dirinfo, NULL, alphasort);
    for(int i=0; i<num; ++i)
    {
      // 编码
      strencode(encoded_name, sizeof(encoded_name), dirinfo->d_name);

      sprintf(path, "%s%s", dirname, dirinfo->d_name);
      printf("############# path = %s\n", path);
      if (lstat(path, &sb) < 0)
      {
            sprintf(buf+strlen(buf),
                  "<tr><td><a href=\"%s\">%s</a></td></tr>\n",
                  encoded_name, dirinfo->d_name);
      }
      else
      {
            strftime(timestr, sizeof(timestr),
                     "%d%b   %Y%H:%M", localtime(&sb.st_mtime));
            if(S_ISDIR(sb.st_mode))
            {
                sprintf(buf+strlen(buf),
                        "<tr><td><a href=\"%s/\">%s/</a></td><td>%s</td><td>%ld</td></tr>\n",
                        encoded_name, dirinfo->d_name, timestr, sb.st_size);
            }
            else
            {
                sprintf(buf+strlen(buf),
                        "<tr><td><a href=\"%s\">%s</a></td><td>%s</td><td>%ld</td></tr>\n",
                        encoded_name, dirinfo->d_name, timestr, sb.st_size);
            }
      }
      bufferevent_write(bev, buf, strlen(buf));
      memset(buf, 0, sizeof(buf));
    }
    sprintf(buf+strlen(buf), "</table></body></html>");
    bufferevent_write(bev, buf, strlen(buf));
    printf("################# Dir Read OK !!!!!!!!!!!!!!\n");

    return 0;
}

void conn_readcb(struct bufferevent *bev, void *user_data)
{
    printf("******************** begin call %s.........\n",__FUNCTION__);
    char buf={0};
    char method, path, protocol;
    bufferevent_read(bev, buf, sizeof(buf));
    printf("buf[%s]\n", buf);
    sscanf(buf, "%[^ ] %[^ ] %[^ \r\n]", method, path, protocol);
    printf("method[%s], path[%s], protocol[%s]\n", method, path, protocol);
    if(strcasecmp(method, "GET") == 0)
    {
      response_http(bev, method, path);
    }
    printf("******************** end call %s.........\n", __FUNCTION__);
}

void conn_eventcb(struct bufferevent *bev, short events, void *user_data)
{
    printf("******************** begin call %s.........\n", __FUNCTION__);
    if (events & BEV_EVENT_EOF)
    {
      printf("Connection closed.\n");
    }
    else if (events & BEV_EVENT_ERROR)
    {
      printf("Got an error on the connection: %s\n",
               strerror(errno));
    }

    bufferevent_free(bev);
    printf("******************** end call %s.........\n", __FUNCTION__);
}

void signal_cb(evutil_socket_t sig, short events, void *user_data)
{
    struct event_base *base = user_data;
    struct timeval delay = { 1, 0 };

    printf("Caught an interrupt signal; exiting cleanly in one seconds.\n");
    event_base_loopexit(base, &delay);
}

void listener_cb(struct evconnlistener *listener,
               evutil_socket_t fd,struct sockaddr *sa, int socklen, void *user_data)
{
    printf("******************** begin call-------%s\n",__FUNCTION__);
    struct event_base *base = user_data;
    struct bufferevent *bev;
    printf("fd is %d\n",fd);
    bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
    if (!bev)
    {
      fprintf(stderr, "Error constructing bufferevent!");
      event_base_loopbreak(base);
      return;
    }
    bufferevent_flush(bev, EV_READ | EV_WRITE, BEV_NORMAL);
    bufferevent_setcb(bev, conn_readcb, NULL, conn_eventcb, NULL);
    bufferevent_enable(bev, EV_READ | EV_WRITE);

    printf("******************** end call-------%s\n",__FUNCTION__);
}

/*
* 这里的内容是处理%20之类的东西!是"解码"过程。
* %20 URL编码中的‘ ’(space)
* %21 '!' %22 '"' %23 '#' %24 '  cjson
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include "cJSON.h"

int main(int argc, const char* argv[])
{
    // 创建对象
    cJSON* obj = cJSON_CreateObject();

    // 创建子对象
    cJSON* subObj = cJSON_CreateObject();
    // 添加key-value
    cJSON_AddItemToObject(subObj, "factory", cJSON_CreateString("一汽大众"));
    cJSON_AddItemToObject(subObj, "last", cJSON_CreateNumber(31));
    cJSON_AddItemToObject(subObj, "price", cJSON_CreateNumber(83));
    cJSON_AddItemToObject(subObj, "sell", cJSON_CreateNumber(49));
    cJSON_AddItemToObject(subObj, "sum", cJSON_CreateNumber(80));

    // 创建json数组
    cJSON* array = cJSON_CreateArray();
    // array添加元素
    cJSON_AddItemToArray(array, cJSON_CreateNumber(123));
    cJSON_AddItemToArray(array, cJSON_CreateBool(1));
    cJSON_AddItemToArray(array, cJSON_CreateString("hello, world"));

    // 数组中的对象
    cJSON* subsub = cJSON_CreateObject();
    cJSON_AddItemToObject(subsub, "梅赛德斯奔驰",
                        cJSON_CreateString("心所向, 持以恒"));
    cJSON_AddItemToArray(array, subsub);

    cJSON_AddItemToObject(subObj, "other", array);

    // obj中添加key - value
    cJSON_AddItemToObject(obj, "奔驰", subObj);

    // 数据格式化
    char* data = cJSON_Print(obj);
    FILE* fp = fopen("car.json", "w");
    fwrite(data, sizeof(char), strlen(data)+1, fp);
    fclose(fp);

    return 0;
}
  mxml
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <mxml.h>

int main(int argc, const char* argv[])
{
    // 文件头
    mxml_node_t *root = mxmlNewXML("1.0");

    // 根标签 -- china
    mxml_node_t* china = mxmlNewElement(root, "china");
    // 子标签 -- city
    mxml_node_t* city = mxmlNewElement(china, "city");
    mxml_node_t* info = mxmlNewElement(city, "name");
    // 标签赋值
    mxmlNewText(info, 0, "北京");
    // 设置属性
    mxmlElementSetAttr(info, "isbig", "Yes");
    // 面积
    info = mxmlNewElement(city, "area");
    mxmlNewText(info, 0, "16410 平方公里");
    // 人口
    info = mxmlNewElement(city, "population");
    mxmlNewText(info, 0, "2171万人");
    // gdp
    info = mxmlNewElement(city, "gdp");
    mxmlNewText(info, 0, "24541亿元");

    // 东京
    city = mxmlNewElement(china, "city");
    info = mxmlNewElement(city, "name");
    // 标签赋值
    mxmlNewText(info, 0, "东京");
    // 设置属性
    mxmlElementSetAttr(info, "isbig", "No");
    // 面积
    info = mxmlNewElement(city, "area");
    mxmlNewText(info, 0, "2188 平方公里");
    // 人口
    info = mxmlNewElement(city, "population");
    mxmlNewText(info, 0, "3670万人");
    // gdp
    info = mxmlNewElement(city, "gdp");
    mxmlNewText(info, 0, "31700亿元");

    // 数据保存到磁盘文件
    FILE* fp = fopen("china.xml", "w");
    mxmlSaveFile(root, fp, MXML_NO_CALLBACK);
   
    fclose(fp);
    mxmlDelete(root);

    return 0;
}


*%25 '%' %26 '&' %27 ''' %28 '('......
*相关知识html中的‘ ’(space)是&nbsp
*/
void encode_str(char* to, int tosize, const char* from)
{
    int tolen;

    for (tolen = 0; *from != '\0' && tolen + 4 < tosize; ++from)
    {
      if (isalnum(*from) || strchr("/_.-~", *from) != (char*)0)
      {
            *to = *from;
            ++to;
            ++tolen;
      }
      else
      {
            sprintf(to, "%%%02x", (int) *from & 0xff);
            to += 3;
            tolen += 3;
      }

    }
    *to = '\0';
}


void decode_str(char *to, char *from)
{
    for ( ; *from != '\0'; ++to, ++from)
    {
      if (from == '%' && isxdigit(from) && isxdigit(from))
      {

            *to = hexit(from)*16 + hexit(from);

            from += 2;                     
      }
      else
      {
            *to = *from;

      }

    }
    *to = '\0';

}

// 通过文件名获取文件的类型
const char *get_file_type(const char *name)
{
    char* dot;

    // 自右向左查找‘.’字符, 如不存在返回NULL
    dot = strrchr(name, '.');   
    if (dot == NULL)
      return "text/plain; charset=utf-8";
    if (strcmp(dot, ".html") == 0 || strcmp(dot, ".htm") == 0)
      return "text/html; charset=utf-8";
    if (strcmp(dot, ".jpg") == 0 || strcmp(dot, ".jpeg") == 0)
      return "image/jpeg";
    if (strcmp(dot, ".gif") == 0)
      return "image/gif";
    if (strcmp(dot, ".png") == 0)
      return "image/png";
    if (strcmp(dot, ".css") == 0)
      return "text/css";
    if (strcmp(dot, ".au") == 0)
      return "audio/basic";
    if (strcmp( dot, ".wav" ) == 0)
      return "audio/wav";
    if (strcmp(dot, ".avi") == 0)
      return "video/x-msvideo";
    if (strcmp(dot, ".mov") == 0 || strcmp(dot, ".qt") == 0)
      return "video/quicktime";
    if (strcmp(dot, ".mpeg") == 0 || strcmp(dot, ".mpe") == 0)
      return "video/mpeg";
    if (strcmp(dot, ".vrml") == 0 || strcmp(dot, ".wrl") == 0)
      return "model/vrml";
    if (strcmp(dot, ".midi") == 0 || strcmp(dot, ".mid") == 0)
      return "audio/midi";
    if (strcmp(dot, ".mp3") == 0)
      return "audio/mpeg";
    if (strcmp(dot, ".ogg") == 0)
      return "application/ogg";
    if (strcmp(dot, ".pac") == 0)
      return "application/x-ns-proxy-autoconfig";

    return "text/plain; charset=utf-8";
}
  new-httpSERVER
[        DISCUZ_CODE_43        ]  libevent - 实现httpdServer
main.c
[        DISCUZ_CODE_44        ]  libevent.h
[        DISCUZ_CODE_45        ]  libevent.c
[        DISCUZ_CODE_46        ]  cjson
[        DISCUZ_CODE_47        ]  mxml
[        DISCUZ_CODE_48        ]

* %25 '%' %26 '&' %27 ''' %28 '('......
* 相关知识html中的‘ ’(space)是&nbsp
*/
void strdecode(char *to, char *from)
{
    for ( ; *from != '\0'; ++to, ++from)
    {
      if (from == '%' && isxdigit(from) && isxdigit(from))
      {
            // 依次判断from中 %20 三个字符
            *to = hexit(from)*16 + hexit(from);
            // 移过已经处理的两个字符(%21指针指向1),表达式3的++from还会再向后移一个字符
            from += 2;
      }
      else
      {
            *to = *from;
      }
    }
    *to = '\0';
}

//16进制数转化为10进制, return 0不会出现
int hexit(char c)
{
    if (c >= '0' && c <= '9')
      return c - '0';
    if (c >= 'a' && c <= 'f')
      return c - 'a' + 10;
    if (c >= 'A' && c <= 'F')
      return c - 'A' + 10;

    return 0;
}

// "编码",用作回写浏览器的时候,将除字母数字及/_.-~以外的字符转义后回写。
// strencode(encoded_name, sizeof(encoded_name), name);
void strencode(char* to, size_t tosize, const char* from)
{
    int tolen;

    for (tolen = 0; *from != '\0' && tolen + 4 < tosize; ++from)
    {
      if (isalnum(*from) || strchr("/_.-~", *from) != (char*)0)
      {
            *to = *from;
            ++to;
            ++tolen;
      }
      else
      {
            sprintf(to, "%%%02x", (int) *from & 0xff);
            to += 3;
            tolen += 3;
      }
    }
    *to = '\0';
}
  cjson
[        DISCUZ_CODE_47        ]  mxml
[        DISCUZ_CODE_48        ]

*%25 '%' %26 '&' %27 ''' %28 '('......
*相关知识html中的‘ ’(space)是&nbsp
*/
void encode_str(char* to, int tosize, const char* from)
{
    int tolen;

    for (tolen = 0; *from != '\0' && tolen + 4 < tosize; ++from)
    {
      if (isalnum(*from) || strchr("/_.-~", *from) != (char*)0)
      {
            *to = *from;
            ++to;
            ++tolen;
      }
      else
      {
            sprintf(to, "%%%02x", (int) *from & 0xff);
            to += 3;
            tolen += 3;
      }

    }
    *to = '\0';
}


void decode_str(char *to, char *from)
{
    for ( ; *from != '\0'; ++to, ++from)
    {
      if (from == '%' && isxdigit(from) && isxdigit(from))
      {

            *to = hexit(from)*16 + hexit(from);

            from += 2;                     
      }
      else
      {
            *to = *from;

      }

    }
    *to = '\0';

}

// 通过文件名获取文件的类型
const char *get_file_type(const char *name)
{
    char* dot;

    // 自右向左查找‘.’字符, 如不存在返回NULL
    dot = strrchr(name, '.');   
    if (dot == NULL)
      return "text/plain; charset=utf-8";
    if (strcmp(dot, ".html") == 0 || strcmp(dot, ".htm") == 0)
      return "text/html; charset=utf-8";
    if (strcmp(dot, ".jpg") == 0 || strcmp(dot, ".jpeg") == 0)
      return "image/jpeg";
    if (strcmp(dot, ".gif") == 0)
      return "image/gif";
    if (strcmp(dot, ".png") == 0)
      return "image/png";
    if (strcmp(dot, ".css") == 0)
      return "text/css";
    if (strcmp(dot, ".au") == 0)
      return "audio/basic";
    if (strcmp( dot, ".wav" ) == 0)
      return "audio/wav";
    if (strcmp(dot, ".avi") == 0)
      return "video/x-msvideo";
    if (strcmp(dot, ".mov") == 0 || strcmp(dot, ".qt") == 0)
      return "video/quicktime";
    if (strcmp(dot, ".mpeg") == 0 || strcmp(dot, ".mpe") == 0)
      return "video/mpeg";
    if (strcmp(dot, ".vrml") == 0 || strcmp(dot, ".wrl") == 0)
      return "model/vrml";
    if (strcmp(dot, ".midi") == 0 || strcmp(dot, ".mid") == 0)
      return "audio/midi";
    if (strcmp(dot, ".mp3") == 0)
      return "audio/mpeg";
    if (strcmp(dot, ".ogg") == 0)
      return "application/ogg";
    if (strcmp(dot, ".pac") == 0)
      return "application/x-ns-proxy-autoconfig";

    return "text/plain; charset=utf-8";
}
  new-httpSERVER
[        DISCUZ_CODE_43        ]  libevent - 实现httpdServer
main.c
[        DISCUZ_CODE_44        ]  libevent.h
[        DISCUZ_CODE_45        ]  libevent.c
[        DISCUZ_CODE_46        ]  cjson
[        DISCUZ_CODE_47        ]  mxml
[        DISCUZ_CODE_48        ]
页: [1]
查看完整版本: Linux Socket 开发代码整理