查看: 64|回复: 0

[转载图文] Linux Socket 开发代码整理

[复制链接]
发表于 2020-6-15 20:53:51 | 显示全部楼层 |阅读模式
  这些代码来自于《传智播客C++全栈开发》系列课程,这里是在学习过程中整理下来的代码,以后用到的话方便直接查阅,这篇文章你可以随意转载无需添加任何处处。
Linux 多线程多进程相关  进程执行命令
#include <stdio.h>
#include <string.h>

int main()
{
FILE *fp = popen("ps -e | grep 'ps' | awk '{print $1}'","r");
char buffer[10]= {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[64] = {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[1024] = {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[i] = toupper(buf[i]);
            }
            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[1]);

    // 创建套接字
    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[64];
            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[1024];
                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[64];
    char buf[1024];
    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[1]);

    // 创建套接字
    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[256];
    // 规定 fd == -1  
    for(i=0; i<sizeof(info)/sizeof(info[0]); ++i)
    {
        info[i].fd = -1;
    }

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

        // 创建子线程 - 通信
        pthread_create(&info[i].id, NULL, worker, &info[i]);
        // 设置线程分离
        pthread_detach(info[i].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[1]);
    // 创建套接字
    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[1024];
        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[BUFSIZ], clie_IP[128];

    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: %s  port:%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[i] = toupper(buf[i]);
        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[BUFSIZ]; 

    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 4096  readn(cfd, buf, 4096)   nleft = 4096-1500
ssize_t Readn(int fd, void *vptr, size_t n)
{
size_t  nleft;              //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[100];

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[MAXLINE];
    char str[INET_ADDRSTRLEN];      //#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[i] = toupper(buf[i]);                           //小写-->大写
        }

        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[256];      //根据最大线程数创建结构体数组.
    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[i].cliaddr = cliaddr;
        ts[i].connfd = connfd;

        pthread_create(&tid, NULL, do_work, (void*)&ts[i]);
        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[MAXLINE];
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_t  nleft;              //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[100];

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[MAXLINE];
    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[MAXLINE];
    char str[INET_ADDRSTRLEN];
    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[i] = toupper(buf[i]);

                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_t  nleft;              //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[100];

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[1024] = {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[128];
    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[1024] = {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[i] = toupper(buf[i]);
        }
        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[1024] = {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[j] = toupper(buf[j]);
                    }
                    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[FD_SETSIZE];   // 1024
    // 记录数组中最后一个元素的下标
    int last_index = 0;
    // 初始化数组
    for(int i=0; i<FD_SETSIZE; ++i)
    {
        allfd[i] = -1;  // 无效文件描述符值
    }
    allfd[0] = 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[64];
        // 判断是否有新连接
        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[i] == -1)
                {
                    allfd[i] = cfd;
                    break;
                }
            }
            // 更新数组最后一个有效值下标
            last_index = last_index < i ? i : last_index; 
        }

        // 遍历检测的文件描述符是否有读操作
        for(i=lfd+1; i<=maxfd; ++i)
        {
            if(FD_ISSET(i, &temps))
            {
                // 读数据
                char buf[1024] = {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[i] = -1;
                    printf("对方已经关闭了连接。。。。。。\n");
                }
                else
                {
                    printf("read buf = %s\n", buf);
                    for(int j=0; j<len; ++j)
                    {
                        buf[j] = toupper(buf[j]);
                    }
                    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[1024];
    int max_index = 0;
    // init
    for(int i=0; i<1024; ++i)
    {
        allfd[i].fd = -1;
    }
    allfd[0].fd = lfd;
allfd[0].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[0].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[i].fd == -1)
                {
                    allfd[i].fd = cfd;
                    break;
                }
            }
            // 更新最后一个元素的下标
            max_index = max_index < i ? i : max_index;
        }

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

    // 创建套接字
    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[2000];
    while(1)
    {
        // 使用epoll通知内核fd 文件IO检测
        int ret = epoll_wait(epfd, all, sizeof(all)/sizeof(all[0]), -1);

        // 遍历all数组中的前ret个元素
        for(int i=0; i<ret; ++i)
        {
            int fd = all[i].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[64] = {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[i].events & EPOLLIN) 
                {
                    continue;
                }

                // 读数据
                char buf[1024] = {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[1]);

    // 创建套接字
    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[2000];
    while(1)
    {            
        // 设置监听
        ret = epoll_wait(epfd, res, sizeof(res)/sizeof(res[0]), -1);
        if(ret == -1)
        {
            perror("epoll_wait error");
            exit(1);
        }

        // 遍历前ret个元素
        for(int i=0; i<ret; ++i)
        {
            int fd = ((SockInfo*)res[i].data.ptr)->fd;
            if(res[i].events != EPOLLIN)
            {
                continue;
            }
            // 判断文件描述符是否为lfd
            if(fd == lfd)
            {
                char ipbuf[64];
                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[64];
                char buf[1024] = {0};
                int len = recv(fd, buf, sizeof(buf), 0);
                SockInfo* p = (SockInfo*)res[i].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[1024] = {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[1024] = {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[64] = {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[1024] = {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[1024] = {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[1024] = {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[1024] = {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[1024] = {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[1024] = {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[1024] = {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[1024] = {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[1024] = {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[1024] = {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[1024] = {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[1024] = {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[1024] = {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[i++] = *p++;

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

    }

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

    }
    protocol[i] = 0;

}

void send_respond_head(int cfd, int size)
{
    char buf[1024] = {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[2]);

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

    // 创建套接字
    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[64];
                // 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[1024];
                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[12], path[1024], protocol[12];
                    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[MAXSIZE];
    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[i];
            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[1024] = {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[1024] = {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[12], path[1024], protocol[12];
    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[4094] = {0};

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

    char enstr[1024] = {0};
    char path[1024] = {0};
    // 目录项二级指针
    struct dirent** ptr;
    int num = scandir(dirname, &ptr, NULL, alphasort);
    // 遍历
    for(int i=0; i<num; ++i)
    {
        char* name = ptr[i]->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[1024] = {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[4096] = {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[i] = c;
            i++;
        }
        else
        {
            c = '\n';
        }
    }
    buf[i] = '\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[64] = {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 '  [b]new-httpSERVER[/b]
[pre]#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[1024] = {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[1024] = {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[1024] = {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[256] = "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[1]);
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[2000];//存epoll_wait传出参数
//通信
while(1)
{
//设置监听  -1一直阻塞,直到有事件才返回
int num = epoll_wait(epfd, all, sizeof(all) / sizeof(all[0]), -1);
if(-1 == num)
{
perror("epoll_wait err");
exit(1);
}

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

//如果fd是监听lfd,说明有新的连接到来
if(fd == lfd)
{
char ipbuf[64];
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[64];//用于通信的时候打印对应客户端的IP
char buf[1024] = {0};
SockInfo * p = (SockInfo *)all[i].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[256] = {0};//存浏览器请求的服务器路径
char path[256] = {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[20] = {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[8192] = {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[2]) < 0) {
        printf("dir is not exists: %s\n", argv[2]);
        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[1]));

    // 创建监听的套接字,绑定,监听,接受连接请求
    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[1];

        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[4096] = {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[256]={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[1024];
    char path[1024];
    char timestr[64];
    struct stat sb;
    struct dirent **dirinfo;

    char buf[4096] = {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[i]->d_name);

        sprintf(path, "%s%s", dirname, dirinfo[i]->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[i]->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[i]->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[i]->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[4096]={0};
    char method[50], path[4096], protocol[32];
    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 '  [b]cjson[/b]
[pre]#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[0] == '%' && isxdigit(from[1]) && isxdigit(from[2]))
        {

            *to = hexit(from[1])*16 + hexit(from[2]);

            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";
}
[/pre]  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[0] == '%' && isxdigit(from[1]) && isxdigit(from[2]))
        {
            // 依次判断from中 %20 三个字符
            *to = hexit(from[1])*16 + hexit(from[2]);
            // 移过已经处理的两个字符(%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';
}
[/pre]  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[0] == '%' && isxdigit(from[1]) && isxdigit(from[2]))
        {

            *to = hexit(from[1])*16 + hexit(from[2]);

            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";
}
[/pre]  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.如果您喜欢这篇帖子,请给作者点赞评分,点赞会增加帖子的热度,评分会给作者加学币。(评分不会扣掉您的积分,系统每天都会重置您的评分额度)。
2.回复帖子不仅是对作者的最好奖励,还可以获得学币奖励,请尊重作者的劳动成果,拒绝做伸手党!
3.发广告、灌水回复等违规行为一经发现直接禁言,如果本帖内容涉嫌违规,请点击论坛底部的举报反馈按钮,也可以在【投诉建议】板块发帖举报。
论坛交流群:672619046
微信公众号
快速回复 返回顶部 返回列表