Linux 多线程与子线程

进程执行命令

#include 
#include

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 
#include

int main()
{

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

子进程:

#include 
#include
#include

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 
#include
#include

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 
#include
#include
#include
#include

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 
#include
#include
#include
#include


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 
#include
#include
#include
#include


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 
#include
#include
#include
#include
#include
#include
#include

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 {
buf[i] = toupper(buf[i]);
}
printf("send buf: %s\n", buf);
write(cfd, buf, len);
}
}

close(lfd);

return 0;
}

TCP 三次握手-并发
process_server.c

#include 
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

// 进程回收函数
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 
#include
#include
#include
#include
#include
#include
#include
#include

// 自定义数据结构
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 {
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 
#include
#include
#include
#include
#include
#include

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 
#include
#include
#include
#include
#include
#include
#include

#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 
#include
#include
#include
#include

#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
#include
#include
#include
#include

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 
#include
#include
#include
#include
#include
#include

#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
#include
#include
#include
#include
#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
#include
#include
#include
#include

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
#include
#include
#include
#include

#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 
#include
#include
#include
#include
#include
#include
#include

#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
#include
#include
#include
#include

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 
#include
#include
#include
#include
#include
#include


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 
#include
#include
#include
#include
#include
#include
#include
#include

// 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 {
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 
#include
#include
#include
#include
#include
#include
#include
#include

#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 {
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 
#include
#include
#include
#include
#include
#include
#include
#include

#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 {
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 {
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 {
buf[j] = toupper(buf[j]);
}
printf("--buf toupper: %s\n", buf);
write(i, buf, strlen(buf)+1);
}
}
}
}

close(lfd);
return 0;
}

pool

#include 
#include
#include
#include
#include
#include
#include
#include
#include

#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 {
buf[k] = toupper(buf[k]);
}
printf("buf toupper: %s\n", buf);
send(fd, buf, strlen(buf)+1, 0);
}

}

}
}

close(lfd);
return 0;
}

epool

#include 
#include
#include
#include
#include
#include
#include
#include
#include


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 {
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 
#include
#include
#include
#include
#include
#include
#include
#include

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 {
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 
#include
#include
#include
#include
#include
#include

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
#include
#include
#include
#include
#include
#include

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 
#include
#include
#include
#include
#include
#include

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 
#include
#include
#include
#include
#include
#include

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 
#include
#include
#include
#include
#include
#include
#include

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 
#include
#include
#include
#include
#include
#include
#include

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 
#include
#include
#include
#include
#include
#include
#include

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 
#include
#include
#include
#include
#include
#include
#include

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 
#include
#include
#include
#include
#include
#include
#include

// 对操作处理函数
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 
#include
#include
#include
#include
#include
#include
#include

// 对操作处理函数
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 
#include
#include
#include
#include
#include
#include
#include


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 
#include
#include
#include
#include
#include
#include
#include
#include

// 读缓冲区回调
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 
#include
#include
#include
#include
#include
#include
#include

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 
#include
#include
#include
#include
#include
#include
#include
#include

// 读缓冲区回调
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 
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

// 进程回收函数
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 
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#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 {
// 只处理读事件, 其他事件默认不处理
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页面

char buf[4094] = {0};

sprintf(buf, "目录名: %s", dirname);
sprintf(buf+strlen(buf), "当前目录: %s
", dirname);

char enstr[1024] = {0};
char path[1024] = {0};
// 目录项二级指针
struct dirent** ptr;
int num = scandir(dirname, &ptr, NULL, alphasort);
// 遍历
for(int i=0; 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),
"",
enstr, name, (long)st.st_size);
}
// 如果是目录
else if(S_ISDIR(st.st_mode))
{
sprintf(buf+strlen(buf),
"",
enstr, name, (long)st.st_size);
}
send(cfd, buf, strlen(buf), 0);
memset(buf, 0, sizeof(buf));
// 字符串拼接
}

sprintf(buf+strlen(buf), "%s
%ld
%s/
%ld
");
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 '$'
* %25 '%' %26 '&' %27 ''' %28 '('......
* 相关知识html中的‘ ’(space)是
*/
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";
}

new-httpSERVER

#include 
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

//#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, "当前路径:%s
\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, "%s\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 
#include
#include
#include
#include
#include
#include
#include
#include
#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

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 
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#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, "%s", dirname);
sprintf(buf+strlen(buf), "当前目录:%s
", dirname);
//添加目录内容
int num = scandir(dirname, &dirinfo, NULL, alphasort);
for(int i=0; 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),
"\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),
"\n",
encoded_name, dirinfo[i]->d_name, timestr, sb.st_size);
}
else
{
sprintf(buf+strlen(buf),
"\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), "%s
%s/
%s
%ld
%s
%s
%ld
");
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 '$'
* %25 '%' %26 '&' %27 ''' %28 '('......
* 相关知识html中的‘ ’(space)是
*/
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';
}

cjson

#include 
#include
#include
#include
#include
#include
#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 
#include
#include
#include
#include
#include
#include

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;
}

版权声明:本博客文章与代码均为学习时整理的笔记,文章 [均为原创] 作品,转载请 [添加出处] ,您添加出处是我创作的动力!