linux服务器编程基础

https://github.com/sogou/workflow/issues/170
https://www.zhihu.com/column/c_127088776
https://github.com/sogou/workflow
你要搞后端,huh。
多进程协程+多线程开发模型。
tcp/udp/http网络协议。
select/poll/epoll非阻塞io调用。
fp,vfs,fs多少得了解点吧。
unix ipc全都得会。
无缓存的文件流io,grpc,erc。。
再算上redis,mysql,apache,zookeeper,k8s,kafka,docker等等一堆的组件得学。
外门语言py,go,cmake,makefile,sh,lua我这些都不算了,算附带的。
//回调函数callback

#include <stdio.h>

void max(int a,int b)
{
        printf("now call max :");
        int t = a > b ? a : b;
        printf("max number is %d\n",t);
}

void min(int a,int b)
{
    printf("now call min:");
    int t = a < b ? a : b;
    printf("min number is %d\n",t);
}

typedef void (*myfun)(int a,int b);

void callback(myfun fun,int a,int b)
{
        fun(a,b);
}


//运算符的重载
/*
除了类属关系运算符"."、成员指针运算符".*"、作用域运算符"::"、sizeof运算符和三目运算符"?:"以外,C++中的所有运算符都可以重载
*/
#include <iostream>

using namespace std;

class coordinate
{
public:
    coordinate(int m_x,int m_y)
    {
        x = m_x;
        y = m_y;
    }
    void operator++();
pubilc:
    int x;
    int y;
}

void coordinate::operator++()
{    
    x = x + 1;
    y = y + 1;
    
}

int main()
{
    coordinate a(4,5);
    ++a;
    cout << a.x << a.y <<endl;
    return 0;
}

(strtok函数)
什么可以直接比较什么不可以直接比较,然后是数组和指针的区别char buf[]和char * buf;


//数组的运算
char *dns_str(char *wanDns_temp,char *wanDns)
{   
    printf("the num is :%s\n",wanDns_temp);
    char *buf = wanDns_temp;
    char pos[123] = {}; 
    int i = 0;
    while(*buf != ' ')
    {   
        wanDns[i] = *buf;
        i++;
        buf++;
    }   
    printf("the pos is :%s\n",wanDns);
}

int main()
{
    char tempDns[32] = {"5.5.5.5 6.6.6.6"};
    char wanDns[32] = {}; 
    dns_str(tempDns,wanDns);
    printf("the wanDns is:%s\n",wanDns);
    return 0;
}
数组和指针


//网络大端序
unsigned short htons(unsigned short);
unsigned short ntohs(unsigned short);
unsigned long htonl(unsigned long);
unsigned long ntohl(unsigned long);

#include <stdio.h>
#include <arpa/inet.h>

int main()
{
    unsigned short host_port = 0x1234;
    unsigned short net_port;
    unsigned long host_addr = 0x12345678;
    unsigned long net_addr;
    
    net_port = htons(host_port);
    net_addr = htonl(host_addr);
    
    printf("Host ordered port: %#x \n",host_port);
    printf("Network ordered port: %#x \n",net_port);
    printf("Host ordered address: %#lx \n",host_addr;
    printf("Network ordered address: %#lx \n",net_port);
    return 0;
    
    
}

//点分十进制转换为32位整数型数据
#include <arpa/inet.h>
/*
*成功时返回32位大端序整数型值,失败返回INADDR_NONE
*同时可以检测无效的的IP地址
*/
in_addr_t inet_addr(const char *string);

#include <stdio.h>
#include <arpa/inet.h>

int main()
{
        char *addr1 = "1.2.3.4";
        char *addr2 = "1.2.3.256";//1个字节能表示的最大整数为255,这里利用错误地址验证inet_addr函数的错误检测能力
        
        unsigened long conv_addr = inet_addr(addr1);
        if(conv_addr == INADDR_NONE)
            printf("Error occured! \n");
        else
            printf("Network ordered integer addr:%#1x \n",conv_addr);
            
        conv_addr = inet_addr(addr2);//这里函数的调用出现异常
        if(conv_addr == INADDR_NONE)
            printf("Error occureded\n");
        else 
            printf("Network ordered interger addr: %#1x \n\n",conv_addr);
        return 0;
}


//异步回调

typedef void(*pcb)(int a);

typedef struct parameter{
    int a;
    pcb callback;
    
}paraneter;

void* callback_thread(void *p1)
{
    parameter *p = (parameter *)p1;
    while(1)
    {
        printf("GetcallBack print! \n");
        sleep(3);
        p->callback(p->a);
    }
}

extern SetCallBackFun(int a,pcb callback)
{
    printf("SetCallBackFun printf\n");
    parameter *p = malloc(sizeof(parameter));
    p->a = 10;
    p->callback = callback;
    
    //创建线程
    pthread_t thing1;
    pthread_create(&thing1,NULL,callback_thread,(viod *)p);
    pthread_join(thing1,NULL);
}

void fCallBack(int a)
{
    printf("a = %d\n",a);
    printf("fCallBack printf !\n");
}

int main()
{
    SetCallBackFun(4,fCallBack);
    return 0;
}

//callback模型与future模型的比

/*
*实际编程中若要调用inet_addr函数,需将转换后的IP地址信息代**入sockaddr_in结构体中声明的in_addr结构体变量。而inet_aton**函数则不需要此过程。原因在于,若传递in_addr结构体变量地址**值,函数会自动把结构填入该结构体变量。
*
*/

//inet_aton.c

#include <stdio.h>
#include <stdlib.h>
#include <arpa/ient.h>
void error_handling(char *message);

int main(int argc,char *argv[])
{
    char *addr = "127.232.124.79";
    struct sockaddr_in addr_inet;
    
    if(!inet_aton(addr,&addr_inet.sin_addr))
        error_handling("Conversion error");
    else
        printf("Network ordered integer addr : %#x \n",
            addr_inet.sin_addr.s_addr);
    return 0;
}

/*
*Makefile如何定义一个变量为空格
*
*/

//#号前有多少个空格,space就被定义为多少空格

empty:=
space:=$(empty) #

//两个$(empty)之间有多少个空格,space就被定义为多少空格

empty:=
space:=$(empty) $(empty)

/*
*查找字符串函数:$(findstring <find> <in>)
*/

/*
*char *inet_ntoa(struct in_addr adr);
*/

/*
*该函数将通过参数传入的整数型IP地址转换为字符串格式并返回
*返回值为char指针,返回字符串地址意味着字符串已保存到内存空*间,但该函数未向程序员要求分配内存,而是在内部申请了内存并*保存了字符串。也就是说,调用完该函数后,应立即将字符串信息*复制到其他内存空间。因为,若在次调用inet_ntoa函数,则有可**能覆盖之前保存的字符串信息。
*
*/

#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>

int main()
{    
    struct sockaddr_in addr1,addr2;
    char *str_ptr;
    char str_arr[20];
    
    addr1.sin_addr.s_addr = htonl(0x1020304);
    addr2.sin_addr.s_addr = htonl(0x1010101);
    
    str_ptr = inet_ntoa(addr1.sin_addr);
    strcpy(str_arr,str_ptr);
    printf("Dotted-Decimal notationl: %s \n",str_ptr);
    
    inet_ntoa(addr2.sin_addr);
    printf("Dotted-Decimal notation2 : %s \n",str_ptr);
    printf("Dotted-Decimal notationl3: %s \n",str_arr);
    return 0;
}

/*
服务器网络地址初始化
memset函数将每个字节初始化为同一值:第一个参数为结构体变量adr的地址,即初始化对象addr;第二个参数为0,因此初始化为0;最后一个参数传入addr的长度,因此addr的所有字节均初始化为0.这样的目的是为了将sockaddr_in结构体中的成员sin_zero初始化为0.
*/

struct sockaddr_in addr;
char * serv_ip = "217.0.0.0"
char * serv_port = "9190"
memset(&addr,0,sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(serv_ip);
addr.sin_port = htons(atoi(serv_port));

/*
服务器端的准备工作通过bind函数完成,而客户端则通过connect函数完成。因此,函数调用前需要准备的地址类型也不同。服务器端声明sockaddr_in结构体变量,将其初始化为赋予服务器端IP和套接字的端口号,然后调用bind函数;而客户端则声明sockaddr_in结构体,并初始化为要与之连接的服务器套接字的IP和端口号,然后调用connect函数
*/

/*
INADDR_ANY
利用常数INADDR_ANY分配服务器的IP地址。若采用这种方式,则可以自动获取运行服务器端的计算机地址。
初始化服务器端套接字时应分配所属计算机的IP地址,因为初始化时使用的IP地址非常明确,那为什么需要进行IP初始化呢?如前所诉,同一计算机中可以分配多个IP地址,实际IP地址的个数和计算机中安装的NIC的数量相等。即使是服务端套接字,也需要决定接受那个IP传来的数据。因此,服务器端套接字初始化过程中要求IP地址。如果只有一个NIC,则直接使用INADDR_ANY。
*/

/*
向套接字分配网络地址
*/
int bind(int sockfd, struct sockaddr *myaddr, socklen_t addrlen);


/*
WSAStringToAddress & WSAAddressToString
两个在Windows下独有的函数,功能和inet_ntoa和inet_addr完全相同
*/

#include <winsock2.h>

/*
ip层
IP本身是面向消息的、不可靠的协议。每次传输数据时会帮我们选择路径,但并不一致。如果传输中发生路径错误,则选择其他路径;但如果发生数据丢失或错误,则无法解决。IP协议无法应对数据错误
*/


/*
*TCP原理
TCP 套接字的数据收发无边界。服务器端即使调用1次write函数传输40字节的数据,客户端也有可能通过4次read函数调用每次读取10字节。但此处有一些疑问,服务器端一次传输了40字节,而客户端居然可以缓慢的分批接收。客户端在接收10字节后,剩下的30字节在何处等候?
实际上,write函数调用后并非立即传输数据,read函数调用后也并非马上接收数据。更准确的说,write函数调用瞬间,数据将移至输出缓冲;read函数调用瞬间,从输入缓冲读取数据。
*/
/*
调用write函数时,数据将移至输出缓冲,在适当的时候(不管是分别传送还是一次性传送)传送对方的输入缓冲。这时对方将调用read函数从输入缓冲读取数据。这些I\O缓冲特性可以整理如下
I\O缓冲在每个TCP套接字中单独存在
I\O缓冲在创建套接字时自动生成
即使关闭套接字也会继续传递输出缓(write)冲中遗留的数据
关闭套接字将丢失输入缓冲中的数据
TCP的滑动窗口可以确保数据不会在缓冲溢出而丢死数据
*/

/*
https://www.jianshu.com/p/57690226c934
TCP内部工作原理1:与对方套接字的连接
1、与对方套接字建立连接
2、与对方套接字进行数据交换
3、断开与对方套接字的连接
*/


/*
如果只考虑可靠性,
*/

/*udp核心函数
#inlcude <sys/socket.h>

ssize_t sendto(int sock,void *buff,size_t nbytes,int flags,struct sockaddr *to,socklen_t addrlen)

ssize_t recvfrom(int sock,void *buff,size_t nbytes,int flags,struct sockaddr *from,socklen_t *addrlen)
*/

/*
sigaction

struct sigaction
{
    void (*sa_handler)(int)
    sigset_t sa_mask;
    int sa_flags;
}
*/

#include <stdio.h>
#include <unistd.h>
#include <signal.h>

void timeout(int sig)
{
        if(sig == SIGALRM)
            puts("Time out!");
        alarm(2);
}

int main(int argc,char *argv[])
{
    int i;
    struct sigaction act;
    act.sa_handler = timeout;
    sigemptyset(&act.sa_mask);
    act.sa_flag = 0;
    sigaction(SIGALRM,&act,0);
    
    alarm(2);
    
    for(i = 0;i < 3;i++)
    {
        puts("wait ...");
        sleep(100);
    }
    return 0;
}

/*
利用信号处理技术消灭僵尸进程
*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>

void read_childproc(int sig)
{
    int status;
    pid_t id = waitpid(-1.&status,WNOHANG);
    if(WIFEXITED(status))
    {
        printf("Removed proc id:\n",id);
        printf("Child send :%d \n",WEXISTATUS(status));
    }
}

int main()
{
    pid_t pid;
    struct sigaction act;
    act.sa_handler = read_childproc;
    sigemptyset(&act.sa_mask);
    &act.sa_flags = 0;
    sigaction(SIGCHLD,&act,0);
    
    pid = fork();
    if(pid == 0)
    {
        puts("Hi ! i am child process");
        sleep(10);
        return 12;
    }else{
        printf("Child proc id :%d \n",pid);
        pid = fork();
        if(pid == 0)
        {
            puts("Hi!i am child process");
            sleep(10);
            exit(24);
        }else{
            int i;
            printf("Child proc id: %d \n",pid);
            for(i = 0;i < 5;i++)
            {
                puts("wait ...");
                sleep(5);
            }
        }
    }
    return 0;
}

/*
多进程回声服务器
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#define BUF_SIZE 30
void error_handling(char *message);
void read_childproc(int sig);

int main()
{
    int serv_sock,clnt_sock;
    struct sockaddr_in serv_adr,clnt_adr;
    
    pid_t pid;
    struct sigaction act;
    socklen_t adr_sz;
    itn str_len,state;
    char buf[BUF_SIZE];
    if(argc != 2){
        printf("Usage : %s <port>\n",argv[0]);
        exit(1);
    }
    
    act.sa_handler = read_childproc;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
    state = sigaction(SIGCHLD,&act,0);
    serv_sock = socket(PF_INET,SOCK_STREAM,0);
    memset(&serv_adr,0,sizeof(serv_adr));
    serv_adr.sin_family = AF_INET;
    serv_adr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_adr.sin_port = htons(atoi(argv[1]));
    
    if(bind(serv_sock,(struct sockaddr*)&serv_adr,sizeof(serv_adr)) == -1)
        error_handling("bind() error");
    if(listen(serv_sock,5) == -1)
        error_handling("listen (0 error");
        
    while(1)
    {
        adr_sz = sizeof(clnt_adr);
        clnt_sock = accept(serv_sock,(struct sockaddr*)&clnt_adr,&adr_sz);
        if(clnt_sock == -1)
            continue;
        else
            puts("new client conneted...");
            
        pid = fork();
        if(pid == -1)
        {
            close(clnt_sock);
            continue;
        }
        if(pid == 0)
        {
            close(serv_sock);//关闭子进程中服务器端的套接字
            while((str_len = read(clnt_sock,buf,BUF_SIZE)) != 0)
            write(clnt_sock,buf,str_len);
            
            close(clnt_sock);
            puts("client disconnetced...");
            return 0;
        }else{
            close(clnt_sock);//关闭父进程中客户端的套接字
        }
        close(serv_sock);
        return 0;
    }
}

void read_childproc(int sig)
{
    pid_t pid;
    int status;
    pid = waitpid(-1,&status,WNOHANG);
    printf("remove proc id :%d \n",pid);
}
/*
*1个套接字中存在2个文件描述符时,只有2个文件描述符都终止(销毁)后,才能销毁*套接字。即使子进程销毁了客户端连接的套接字文件描述符,也无法完全销毁套接字**,因此,调用fork函数后,要将无关紧要的套接字文件描述符关掉。
*/

/*
*管道并非属于进程的资源,而是和套接字一样,属于操作系统(也就不是fork函数的复制对象),所以,两个进程通过操作系统提供的内存空间进行通信
*/

/*
*客户端分割TCP的I/O程序
*/

/*
*进程间通信
*/

/*
*管道pipe
*int pipe(int filedes[2]);
*filedes[0]:管道出口
*filedes[1]:管道入口
*/

#include <stdio.h>
#include <unistd.h>
#define BUF_SIZE 30

int main(int argc,char *argv[])
{
    int fds[2];
    char str[] = "Who are you?";
    char buf[BUF_SIZE];
    pid_t pid;
    
    pid(fds);
    pid = fork();
    if(pid == 0)
    {
        write(fds[1],str,sizeof(str));
    }else{
        read(fds[0],buf,BUF_SIZE);
        puts(buf);
    }
    
    return 0;
}

/*
*利用进程保存消息的回声服务器
*/

int main(int argc,char *argv[])
{
    int serv_sock,clnt_sock;
    struct sockaddr_in serv_adr,clnt_adr;
    int fds[2];
    
    pid_t pid;
    struct sigaction act;
    socklen_t adr_sz;
    int str_len,state;
    char buf[BUF_SIZE];
    if(argc!=2){
        printf("Usage : %s <port>\n,argv[0]");
        exit(1);
    }
    act.sa_handler = read_childproc;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
    state = sigaction(SIGCHLD,&act,0);
    
    serv_sock = socket(PF_INET,SOCK_STREAM,0);
    memset(&serv_adr,0,sizeof(serv_adr));
    serv_adr.sin_family = AF_INET;
    serv_adr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_adr.sin_port = htons(atoi(argv[1]));
    
    if(bind(serv_sock,(struct sockaddr*)&serv_adr,sizeof(serv_adr)) == -1)
        error_handling("bind()error");
    if(listen(serv_sock,5) == -1)
        error_handling("listen()error");
        
    pipe(fds);
    pid = fork();
    if(pid == 0)
    {
        FILE *fp = fopen("echomsg.txt","wt");
        char msgbuf[BUF_SIZE];
        int i,len;
        
        for(i = 0;i < 10;i++)
        {
            len = read(fds[0],msgbuf,BUF_SIZE);
            fwrite((void*)msgbuf,1,len,fp);
        }
        fclose(fp);
        return 0;
    }
    while(1)
    {
        adr_sz = sizeof(clnt_adr);
        clnt_sock = accept(serv_sock,(struct sockaddr*)&clnt_adr,&adr_sz);
        if(clnt_sock == -1)
            continue;
        else    
            puts("new clinet connect...");
            
        pid = fork();
        if(pid == 0)
        {
            close(serv_sock);
            while((str_len = read(clnt_sock,buf,BUF_SIZE))!=0)
            {
                write(clnt_sock,buf,str_len);//回声
                write(fds[1],buf,str_len);
            }
            close(clnt_sock);
            puts("clinet disconnetced...");
            return 0;
        }else
            close(clnt_sock);
    }
    close(serv_sock);
    return 0;
}

/*
*I/O复用:select函数
*为了构建并发服务器,只要客户端连接请求就会创建新进程。这的确是实际操作中采用的一种方案,但是因为创建进程需要大量的运算和内存空间,由于每个进程都具有独立的内存空间,所以相互间的数据交换也要求采用相对复杂的方法(IPC属于相对复杂的方法)。
IO复用能在不创建进程的同时向多个客户端提供服务。
*/

fd_set数组是以位为单位进行操作的,使用相关宏进行操作置位
FD_ZERO(fd_set *fdset);
FD_SET(int fd,fd_set *fdset);
FD_CLR(int fd,fd_set *fdset);
FD_ISSET(int fd,fd_set *fdset);

#include <sys/select.h>
#include <sys/time.h>

int select(int maxfd,fd_set *readset,fd_set *writeset,fd_set *exceptset,const struct timeval *timeout)

/*
*select 函数调用示例
*/

#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/select.h>
#define BUF_SIZE 30;

int main()
{
    fd_set reads,temps;
    int result,str_len;
    char buf[BUF_SIZE];
    struct timeval timeout;
    
    FD_ZERO(&reads);
    FD_SET(0,&reads);//0 is standed input(console)
    
    /*
        timeout.tv_sec = 5;
        timeout.tv_usec = 5000;
    */
    
    while(1)
    {
        temps = reads;
        timeout.tv_sec = 5;
        timeout.tv_usec = 0;
        result = select(1,&temp,0,0,&timeout);
        if(result == -1)
        {
            puts("select () error!");
        }else if(result == 0){
            puts("time out !");
        }else{
            if(FD_ISSET(0,&temps))
            {
                str_len = read(0,buf,BUF_SIZE);
                buf[str_len] = 0;
                printf("message form console ; %s\n",buf);
            }
        }
    }
    return 0;
}

/*实现IO复用服务端*/

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

#define BUD_SIZE 100
void error_handling(char *buf);

int main()
{
    int serv_sock,clnt_sock;
    struct sockaddr_in serv_adr,clnt_adr;
    struct timeval timeout;
    fd_set reads,cpy_reads;
    
    socklen_t adr_sz;
    
    int fd_max,str_len,fd_num,i;
    char buf[BUF_SIZE];
    
    if(argc != 2){
        printf("Usage : %s <port>\n,argv[0]");
        exit(1);
    }
    
    serv_sock = socket(PF_INET,SOCK_STREAM,0);
    memset(&serv_adr,0,sizeof(serv_adr));
    serv_adr.sin_family = AF_INET;
    serv_adr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_adr.sin_port = htons(atoi(argv[1]));
    
    if(bind(serv_sock,(struct sockaddr*)&serv_adr,sizeof(serv_adr)) == -1)
        error_handling("bind()error");
    if(listen(serv_sock,5) == -1)
        error_handling("listen()error");
    
    FD_ZERO(&reads);
    FD_SET(serv_sock,&reads);
    fd_max = serv_sock;
    
    while(1)
    {
        cpy_reads = reads;
        timeout.tv_sec = 5;
        timeout.tv_usec = 5000;
        
        if((fd_num = select(fd_max+1,&cpy_reads,0,0,&timeout)) ==-1)
            break;
        if(fd_num == 0)
            continue;
            
        for(i = 0;i < fd_max+1;i++)
        {
            if(FD_ISSET(i,&cpy_reads))
            {
                if(i == serv_sock)
                {
                    adr_sz = sizeof(clnt_adr);
                    clnt_sock = accept(serv_sock,(struct sockaddr*)&clnt_adr,&adr_sz);
                    FD_SET(clnt_sock,&read);
                    if(fd_max < clnt_sock)
                        fd_max = clnt_sock;
                    printf("connected client : %d\n",clnt_sock);
                }else{
                    //read message
                    str_len = read(i,buf,BUF_SIZE);
                    if(str_len == 0) //close request
                    {
                        FD_CLR(i,&read);
                        close(i);
                        printf("close client : %d \n",i);
                    }else{
                        write(i,buf,str_len);//echo
                    }
                }
            }
        }
    }
    close(serv_sock);
    return 0;
}

/*
*多种IO函数
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>

#define BUF_SIZE 30
void error_handling(char *message);
void urg_handler(int signo);

int acpt_sock;
int recv_sock;

int main(int argc,char *argv[])
{
    struct sockaddr_in recv_adr,serv_adr;
    int str_len,state;
    socklen_t serv_adr_sz;
    struct sigaction act;
    char buf[BUF_SIZE];
    if(argc != 2)
    {
        printf("Usage : %s <port>\n,argv[0]");
        exit(1);
    }
    
    act.sa_handler = urg_handler;
    sigemptyset(&act.sa_mask);
    act.sa_flag = 0;
    
    acpt_sock = socket(PF_INET,SOCK_STREAM,0);
    memset(&serv_adr,0,sizeof(recv_adr));
    recv_adr.sin_family = AF_INET;
    recv_adr.sin_addr.s_addr = htonl(INADDR_ANY);
    recv_adr.sin_port = htons(atoi(argv[1]));
    
    if(bind(acpt_sock,()))
}


/*TTL设置*/
/*
*程序中的TTL的设置。程序中的TTL设置是通过套接字的可选项完成的。与设置TTL相关的协议为IPPROTO_IP,选项名为IP_MULTICAST_TTL.因此用如下代码把TTL设置为64
*/
int send_sock;
int time_live = 64;
send_sock = socket(PF_INET,SOCK_STREAM,0);
setsockopt(send_sock,IPPROTO_IP,IP_MULTICAST_TTL,(void *)&time_live,sizeof(time_live));

IO流的分离
/*
*复制文件描述符后“流”的分离
*/
无论复制出多少文件描述符,均应调用shutdown函数发送EOF并进入半关闭状态。

/*
*epoll
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/epoll.h>

#define BUF_SIZE 100
#define EPOLL_SIZE 50
void error_handling(char *buf)

int main(int argc,char argv[])
{
    int serv_sock,clnt_sock;
    struct sockaddr_in serv_adr,clnt_adr;
    socklen_t adr_sz;
    int str_len,i;
    char buf[BUF_SIZE];
    
    struct epoll_event *ep_events;
    struct epoll_event event;
    itn epfd,event_cnt;
    
    if(argc != 2){
        printf("Usage : %s <port>\n",argv[0]);
        exit(1);
    }
    
    serv_sock = socket(AF_INET,SOCK_STREAM,0);
    memset(&serv_adr,0,sizeof(serv_adr));
    serv_adr.sin_family = AF_INET;
    serv_adr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_adr.sin_port = htons(atoi(argv[1]));
    
    if(bind(serv_sock,(struct sockaddr*)&serv_adr,sizeof(serv_adr)) == -1)
        error_handling("bind() error");
    if(listen(serv_sock,5) == 1)
        error_handling("listen () error");
    
    epfd = epoll_create(EPOLL_SIZE);
    ep_events = malloc(sizeof(struct epoll_events)*EPOLL_SIZE);
    
    event.events = EPOLLIN;
    event.data.fd = serv_sock;
    epoll_ctl(epfd,EPOLL_CTL_ADD,serv_sock,&event);
    
    while(1)
    {
        event_cnt = epoll_wait(epfd,ep_events,EPOLL_SIZE,-1);
        if(event_cnt == -1)
        {
            puts("epoll_wait()error");
            break;
        }
        
        for(i=0;i<event_cnt;i++)
        {
            if(ep_events[i].data.fd == serv_sock)
            {
                adr_sz = sizeof(clnt_adr);
                clnt_sock = accept(serv_sock,(struct sockaddr*)&clnt_adr,&adr_sz);
                event.events = EPOLLIN;
                event.data.fd = clnt_sock;
                epoll_ctl(epfd,EPOLL_CTL_ADD,clnt_sock,&event);
                printf("connected client : %d \n",clnt_sock);
            }else{
                str_len = read(ep_events[i].data.fd,buf,BUF_SIZE);
                if(str_len == 0)//close requests
                {
                    epoll_ctl(epfd,EPOLL_CTL_DEL,ep_events[i].data.fd,NULL);
                    close(ep_events[i].data.fd);
                    printf("close client:%d\n",ep_events[i].data.fd);
                }else{
                    write(ep_events[i].data.fd,buf,str_len);//echo
                }
            }
        }
    }
    close(serv_sock);
    close(epfd);
    return 0;
}

/*
条件触发和边缘触发
条件触发方式中,只要输入缓冲有数据就会一直通知该事件
服务器端输入缓冲收到50字节的数据时,服务器端操作系统将通知该事件(注册到发生变化的文件描述符中)。但服务器端读取20字节后还剩30字节的情况下,仍会注册事件。也就是说,条件触发方式下,只要输入0缓冲中还剩下数据,就将以事件的方式在次注册。
边缘触发的事件特性:边缘触发中输入缓冲收到数据时仅注册1次改该事件。即使输入缓冲中还留有数据,也不会在进行注册。
epoll默认以条件触发的方式工作
*/

//条件触发
#include <>
#define BUF_SIZE 4
#define EPOLL_SIZE 50


int main()
{
    int serv_sock,clnt_sock;
    struct sockaddr_in serv_adr,clnt_adr;
    socklen_t adr_sz;
    int str_len,i;
    char buf[BUF_SIZE];
    
    struct epoll_event *ep_events;
    struct epoll_event event;
    
    int epfd,event_cnt;
    
    if(argc != 2)
    {
        printf("Usage : %s <port>\n ",argv[0]);
        exit(1);
    }
    
    serv_sock = socket(PF_INET,SOCK_STREAM,0);
    memset(&serv_adr,0,sizeof(serv_adr));
    serv_adr.sin_family = AF_INET;
    serv_adr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_adr.sin_port = htons(atoi(argv[1]));
    
    if(bind(serv_sock,(strcut sockaddr*)&serv_adr,sizeof(serv_adr)) == -1)
        error_handling("bind()error");
    if(listen(send_sock,5) == -1)
        error_handling("listen()error");
    
    epfd = epoll_create(EPOLL_SIZE);
    ep_events = malloc(sizeof(struct epoll_event)*EPOLL_SIZE);
    
    event.events = EPOLLIN;
    event.data.fd = serv_adr;
    epoll_ctl(epfd,EPOLL_CTL_ADD,serv_sock,&event);
    
    while(1)
    {
        event_cnt = epoll_wait(epfd,ep_events,EPOLL_SIZE,-1);
        if(event_cnt == -1)
        {
            puts("epoll_wait()error");
            break;
        }
        
        puts("return epoll_wait");
        for(i = 0;i < event_cnt;i++)
        {
            if(ep_events[i].data.fd == serv_sock)
            {
                adr_sz = sizeof(clnt_adr);
                clnt_sock = accept(serv_sock,(struct sockaddr*)&clnt_adr,&adr_sz);
                event.events = EPOLLIN;
                event.data.fd = clnt_sock;
                epoll_ctl(epfd,EPOLL_CTL_ADD,clnt_sock,&event);
                printf("conneted client : %d\n",clnt_sock);
            }else{
                str_len = read(ep_events[i].data.fd,buf,BUF_SIZE);
                if(str_len == 0) //close request
                {
                    epoll_ctl(epfd,EPOLL_CTL_DEL,ep_events[i].data.fd,NULL);
                    close(ep_events[i].data.fd);
                    printf("close client : %d \n",ep_events[i].data.fd);
                }else{
                    write(ep_events[i].data.fd,buf,str_len);
                }
            }
        }
    }
}

//边缘触发:
event.events = EPOLLIN|EPOLLET;
//select模型是以条件触发的方式工作的,输入缓冲中如果还剩有数据,肯定会注册事件。


边缘触发的服务器端实现中必知的两点:
1、通过errno变量验证错误的原因
2、为了完成非阻塞(Non-blocking)I/O,更改套接字特性


int fcntl(int filedes,int cmd,...)
int flag = fcntl(fd,F_GETFL,0);
fcntl(fd,F_SETFL,flag|O_NONBLOCk);
通过第一条语句获取之前的设置的属性信息,通过第二条语句在此基础上添加非阻塞O_NONBLOCK标志。调用read&write函数时,无论是否存在数据,都会形成非阻塞文件(套接字)。fcntl函数的适用范围很广。

边缘触发方式下,以阻塞方式工作的read&write函数有可能引起服务器端的长时间停顿。因此,边缘触发方式中一定要采取非阻塞read&wrote函数。

示例:
#include <fcntl.h>
#include <erron.h>
#define BUF_SIZE 4
#define EPOLL_SIZE 50

void setnonblockingmode(int fd);
void error-handling(char *buf);

int main(int argc,char *argv[])
{
    int serv_sock,clnt_sock;
    struct sockaddr_in serv_adr,clnt_adr;
    socklen_t adr_sz;
    int str_len,i;
    char buf[BUF_SIZE];
    
    struct epoll_event *ep_events;
    struct epoll_event event;
    int epfd,event_cnt;
    if(argc!=2)
    {
        printf("Usage : %s <port>\n",argv[0]);
        exit(1);
    }
    
    serv_sock = socket(PF_INET,SOCK_STREAM,0);
    memset(&serv_adr,0,sizeof(serv_adr));
    serv_adr.sin_family = AF_INET;
    serv_adr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_adr.sin_port = htons(atoi(argv[1]));
    
    if(bind(serv_sock,(struct sockaddr*)&serv_adr,sizeof(serv_adr)) == -1)
        error_handling("bind()error");
    if(listen(serv_sock,5) ==-1)
        error_handling("listen () error");
    
    epfd = epoll_create(EPOLL_SIZE);
    ep_events = malloc(sizeof(struct epoll_event)*EPOLL_SIZE);
    
    setnonblockingmode(serv_sock);
    event.events = EPOLLIN;
    event.data.fd = serv_sock;
    epoll_ctl(epfd,EPOLL_CTL_ADD,serv_sock,&event);
    
    while(1)
    {
        event_cnt = epoll_wait(epfd,ep_events,EPOLL_SIZE,-1);
        if(event_cnt == -1)
        {
            puts("epoll_wait()error");
            break;
        }
        
        puts("return epoll_wait");
        for(i=0;i < event_cnt;i++)
        {
            if(event_cnt == serv_sock)
            {
                adr_sz = sizeof(clnt_adr);
                clnt_sock = accept(serv_sock,(struct sockaddr*)&clnt_adr,&adr_zs);
                event.events = EPOLLIN | EPOLLET;
                event.data.fd = clnt_sock;
                epoll_ctl(epfd,EPOLL_CTL_ADD,clnt_sock,&event);
                printf("connect client ; %d \n",clnt_sock);
            }else{
                while(1)
                {
                    str_len=read(ep_events[i].data.fd,buf,BUF_SIZE);
                    if(str_len == 0){//close request???
                        epoll_ctl(epfd,EPOLL_CTL_DEL,ep_events[i].data.fd,NULL);
                        printf("close client : %d\n",ep_events[i].data.fd);
                        break;
                    }else if(str_len < 0){
                        if(errno == EAGAIN)
                        break;
                    }else{
                        write(ep_events[i].data.fd,buf,str_len);
                    }
                }
            }
        }
    }
    close(serv_sock);close(epfd);
    return 0;
}

void setnonblockingmode(int fd)
{
    int flag = fcntl(fd,F_GETFL,0);
    fcntl(fd,F_SETFL,flag|O_NONBLOCK);
}

/*
*linux的线程学习

*/

每个进程的内存空间都由保存全局变量的数据区、向malloc等函数的动态分配提供空间的堆、函数运行时使用的栈构成。每个进程都拥有这种独立空间。为了得到多条代码执行流而复制整个内存区域的负担太重。如果只需要以获得多个代码执行流为主要目的,则只需要分离栈区域。通过这种方式可以的好处是:
1、上下文切换时不需要切换数据区和堆
2、可以利用数据区和堆交换数据
实际上这就是线程。线程为了保持多条代码执行流而隔离开了栈区域。
多个线程将共享数据区和堆,为了保持这种结构,线程将在进程内创建并运行。
进程:在操作系统构成单执行流的单位
线程:在进程构成单执行流的单位

线程的创建及运行
#incude <pthread.h>
int pthread_create(
    pthread_t * restrict thread,const pthread_attr_t *restrict attr,
    void *(* start_routine)(void *),void *restrict arg
);

#include <stdio.h>
#include <pthread.h>
void * thread_main(void *arg)

int main(int argc,char *argv[])
{
    pthread_t t_id;
    int thread_param = 5;
    
    if(pthread_create(&t_id,NULL,thread_main,(void*)&thread_param)!=0)
    {
        puts("pthread_create()error");
        return -1;
    };
    sleep(10);puts("end of main");
    return 0;
}

void *thread_main(void *arg)
{
    int i;
    int cnt = *((int *)arg);
    for(i = 0;i < cnt;i++)
    {
        sleep(1);puts("running thread");
    }
    return NULL;
}


/*
*调用该函数的进程将进入等待状态,直到一个参数为ID的线程终止为止。而且可以得到线程的main函数返回值。
*
*/

int pthread_join(pthread_t thread,void **status);

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
void *thread_main(void *arg);

int main(int argc,char *argv[])
{
    pthread_t t_id;
    int thread_param = 5;
    void * thr_ret;
    
    if(pthread_create(&t_id,NULL,thread_main,(void*)&thread_param)!=0)
    {
        puts("pthread_create()error");
        return -1;
    };
    
    if(pthread_join(t_id,&thr_ret)!=0)
    {
        puts("pthread_join()error");
        return -1;
    }
    
    printf("Thread return message : %s \n",(char*)thr_ret);
    free(thr_ret);
    return 0;
}

void *thread_main(void *arg)
{
    int i;
    int cnt=*((int *)arg);
    char *msg = (char *)malloc(sizeof(char)*50);
    strcpy(msg,"hello,iam thread~\n");
    
    for(i = 0;i < cnt;i++)
    {
        sleep(1);puts("runing thread");
    }
    return (void*)msg;
}
/*线程返回值的方法,注意返回值是threa_main函数内部动态分配的内存空间地址值*/
根据临界区是否引起问题,函数可分为
1、线程安全函数
2、非线程安全函数


/*
*工作线程模式
*/
#include <stdio.h>
#include <pthread.h>
void * thread_summation(void *arg);
int sum = 0;

int main(int argc,char *argv[])
{
    pthrea_t id_t1,id_t2;
    itn range1[] = {1,5};
    int range2[] = {6,10};
    
    pthread_create(&id_t1,NULL,thread_summation,(void *)range1);
    pthread_create(&id_t2,NULL,thread_sunmation,(void *)range2);
    
    pthread_join(id_t1,NULL);
    pthread_join(id_t2,NULL);
    printf("result :%d\n",sum);
    return 0;
}

void *thread_summation(void *arg)
{
    int start = ((int*)arg)[0];
    int end = ((int *)arg)[1];
    
    while(start<=end)
    {
        sum+=start;
        start++;
    }
    return NULL;
}

互斥量
int pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutexattr_t *attr);
int pthread_mutex_destroy(pthread_mutex_t * mutex);

利用互斥量锁住或释放临界区时使用的函数
int pthread_mutex_lock(pthread_mutex_t * mutex)
int pthread_mutex_unlock(pthread_mutex_t * mutex)


/**
多线程并发服务器端的实现
**/

#include <"">
#define BUF_SIZE 100
#define MAX_CLNT 256

void *handle_clnt(void *arg);
void send_msg(char *msg,int len);
void error_handling(char *msg);

int clnt_cnt = 0;
int clnt_socks[MAX_CLNT];
pthread_mutex_t mutx;

int main(int argc,char &argv[])
{
    int serv_sock,clnt_sock;
    struct sockaddr_in serv_adr,clnt_adr;
    int clnt_adr_sz;
    pthread_t t_id;
    if(argc != 2)
    {
        printf("Usage : %s<port>\n",argv[0]);
        exit(1);
    }
    
    pthread_mutex_init(&mutx,NULL);
    serv_sock = socket(PF_INET,SOCK_STREAM,0);
    
    memset(&serv_sock,0,sizeof(serv_adr));
    serv_adr.sin_family = AF_INET;
    serv_adr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_adr.sin_port = htons(atoi(argv[1]));
    
    if(bind(serv_sock,(struct sockaddr*)&serv_adr,sizeof(serv_adr)) == -1)
        error_handling("bind()error");
    if(listen(serv_sock,5) ==-1)
        error_handling("listen() error");
        
    while(1)
    {
        clnt_adr_sz = sizeof(clnt_adr);
        clnt_sock = accept(serv_sock,(struct sockaddr*)&clnt_adr,&clnt_adr_sz);
        
        pthread_mutex_lock(&mutx);
        clnt_socks[clnt_cnt++] = clnt_sock;
        pthread_mutex_unlock(&mutx);
        
        pthread_create(&t_id,NULL,handle_clnt,(void*)&clnt_sock);
        pthread_detach(t_id);
        printf("Connect client IP : %s \n",inet_ntoa(clnt_adr.sin_addr));
        close(serv_sock);
        return 0;
    }
}

void *handle_clnt(void *arg)
{
    int clnt_sock = *((int *)arg);
    int srt_len = 0,i;
    char msg[BUF_SIZE];
    
    while((str_len = read(clnt_sock,msg,sizeof(msg)) != 0)
        send_msg(msg,str_len);
    pthread_mutex_lock(&mutx);
    for(i=0;i<clnt_cnt;i++)//remove disconnected client
    {
        if(clnt_sock == clnt_sock[i])
        {
            while(i++<clnt_cnt-1)
                clnt_socks[i] = clnt_socks[i+1];
            break;
        }
    }
    clnt_cnt--;
    pthread_mutex_unlock(&mutx);
    close(clnt_sock);
    return NULL;
}

void send_msg(char *msg,int len) // send to all
{
    int i;
    pthread_mutex_lock(&mutx);
    for(i=0;i<clnt_cnt;i++)
        write(clnt_sock[i],msg,len);
    pthread_mutex_unlock(&mutx);
}

void error_handling(char *msg)
{
    
}

/*client_c*/
#include <>
#define BUF_SIZE 100
#define NAME_SIZE 20

void *send_msg(void *arg)
void *recv_msg(void *arg)
void error_handling(char *msg)

char name[NAME_SIZE] = "[DEFAULT]";
char msg[BUF_SIZE];

int main(int argc,char *argv[])
{
    int sock;
    strcut sockaddr_in serv_addr;
    pthread_t snd_thread,rcv_thread;
    void *thread_return;
    if(argc != 4){
        printf("Usage : %s <IP><port><name>\n",argv[0]);
        exit(1);
    }
    
    sprintf(name,"[%s]",argv[3]);
    sock = socket(PF_INET,SOCK_STREAM,0);
    
    memset(&serv_addr,0,sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = inet_addr(argv[1]);
    serv_addr.sin_port = htons(atoi(argv[2]));
    
    if(connect(sock,(struct sockaddr*)&serv_addr,sizeof(serv_addr)) == -1)
        error_handling("connect()error");
    
    pthread_create(&snd_thread,NULL,send_msg,(void*)&sock);
    pthread_create(&rcv_thread,NULL,recv_msg,(void*)&sock);
    pthread_jion(snd_thread,&thread_return);
    pthread_jion(rev_thread,&thread_return);
    close(sock);
    return 0;
}

void *send_msg(void *arg) //send thread main
{
    int sock = *((int*)arg);
    char name_msg[NAME_SIZE+BUF_SIZE];
    
    while(1)
    {
        fgets(msg,BUF_SIZE,stdin);
        if(!strcmp(msg,"q\n")||!strcmp(msg,"Q\n"))
        {
            close(sock);
            exit(1);
        }
        sprintf(name_msg,"%s %s",name,msg);
        write(sock,name_msg,strlen(name_msg));
    }
    return NULL;
}

void *recv_msg(void *arg)  //read thread main
{
    int sock = *((int *)arg);
    char name_msg[NAME_SIZE+BUF_SIZE];
    int str_len;
    while(1)
    {
        str_len = read(sock,name_msg,NAME_SIZE+BUF_SIZE-1);
        if(str_len == -1)
            return (void*)-1;
        name_msg[str_len] = 0;
        fputs(name_msg,stdout);
    }
    return NULL;
}

void error_handling(char *msg)
{
    
}

/*************************************************************/
/****************************实现udp的可靠传输***************/
/*server端*/
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netistd.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <netdb.h>
#include <stdarg.h>
#include <string.h>

#define SERVER_PORT 8000
#define BUFFER_SIZE 1024
#define FILE_NAME_MAX_SIZE 512

/*包头*/
typedef struct
{
    int id;
    int buf_size;
}PackInfo

/*接受包*/
struct SendPack
{
    PackInfo head;
    char buf[BUFFER_SIZE];
}data;

int main()
{
    /*发送Id*/
    int send_id = 0;
    
    /*接收ID*/
    int receive_id = 0;
    
    /*创建UDP套接口*/
    struct sockaddr_in server_addr;
    bzero(&server_addr,sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    server_addr.sin_port = htons(atoi(SERVER_PORT));
    
    /*创建socket*/
    int server_socket_fd = socket(AF_INET,SOCK_DGRAM,0);
    if(server_socket_fd == -1)
    {
        perror("Create Socket Failed:");
        exit(1);
    }
    
    /*绑定套接口*/
    if(-1 == (bind(server_socket_fd,(struct sockaddr*)&server_addr,sizeof(server_addr))))
    {
        perror("Server Bind Failed:");
        exit(1);
    }
    
    /*数据传输*/
    while(1)
    {
        /*定义一个地址,用于捕获客户端地址*/
        struct sockaddr_in client_addr;
        socklen_t client_addr_length = sizeof(client_addr);
        
        /*接受数据*/
        char buffer[BUFFER_SIZE];
        bzero(buffer,BUFFER_SIZE);
        if(recvfrom(server_socket_fd,buffer,BUFFER_SIZE,0,(struct sockaddr*)&client_addr,sizeof(client_addr)))
        {
            perror("Receive Data Failed:");
            exit(1);
        }
        
        /*从buffer中拷出file_name*/
        char file_name[FILE_NAME_MAX_SIZE+1];
        bzero(file_name,FILE_NAME_MAX_SIZE+1);
        strncpy(file_name,buffer,strlen(buffer)>FILE_NAME_MAX_SIZE?FILE_NAME_MAX_SIZE:strlen(buffer));
        printf();
    }
}
/************************************************************/


/***********************linux hhtp***************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <pthread.h>

#define BUF_SIZE 1024
#deiine SMALL_BUF 100

void* request_handler(void* arg);
void send_data(FILE *fp,char* ct,char* file_name);
char* content_type(char *file);
void send_error(FILE *fp);
void error_handling(char* message);

int main(int argv,char *argv[])
{
    int serv_sock,clnt_sock;
    struct sockaddr_in serv_addr,clnt_adr;
    int clnt_adr_size;
    char buf[BUF_SIZE];
    pthread_t t_id;
    if(argc != 2)
    {
        printf("Usage : %s<port>\n",argv[0]);
        exit(1);
    }
    
    serv_sock = socket(PF_INET,SOCK_STREAM,0);
    memset(&serv_adr,0,sizeof(serv_adr));
    serv_adr.sin_family = AF_INET;
    serv_adr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_adr.sin_port = htons(atoi(argv[1]));
    if(bind(serv_sock,(struct sockaddr*)serv_adr,sizeof(serv_adr)) ==-1)
        error_handling("bind() error");
    if(listen(serv_sock,20) ==-1)
        error_handling("listen() error");
    
    while(1)
    {
        clnt_adr_size = sizeof(clnt_adr);
        clnt_sock = accept(serv_sock,(struct sockaddr*)&clnt_adr,&clnt_adr_size);
        printf("Connection Requset : %s:%d\n",inet_ntoa(clnt_adr.sin_addr),ntohs(clnt_adr.sin_port));
        pthread_create(&t_id,NULL,request_handler,&clnt_sock);
        pthread_detach(t_id);
    }
    close(serv_sock);
    return 0;
}

void *request_handler(void *arg)
{
    int clnt_sock = *((int *)arg);
    char req_line[SMALL_BUF];
    FILE *clnt_read;
    FILE *clnt_write;
    
    char method[10];
    char ct[15];
    char file_name[30];
    
    clnt_read = fdopen(clnt_sock,"r");
    clnt_write = fdopen(dup(clnt_sock),"w");
    fgets(reg_line,SMALL_BUF,clnt_read);
    if(strstr(req_line,"HTTP/") == NULL)
    {
        send_error(clnt_write);
        fclose(clnt_read);
        fclose(clnt_write);
        return ;
    }
    fclose(clnt_send);
    send_data(clnt_write,ct,file_name);
}

void send_data(FILE *fp,char *ct,char *file_name)
{
    char protocol[] = "HTTP/1.0 200 OK\r\n";
    char server[] = "Server:Linux Web Server \r\n";
    char cnt_len[] = "Content-length : 2048\r\n";
    char cnt_type[SMALL_BUF];
    char buf[BUF_SIZE];
    FILE *send_file;
    
    sprintf(cnt_type,"Content-type:%s\r\n\r\n",ct);
    send_file = fopen(file_name,"r");
    if(send_file == NULL)
    {
        send_error(fp);
        return ;
    }
    
    /*传输头信息*/
    fputs(protocol,fp);
    fputs(server,fp);
    fputs(cnt_len,fp);
    fputs(cnt_type,fp);
    
    /*传输请求数据*/
    while(fgets(buf,BUF_SIZE,send_file) != NULL)
    {
        fputs(buf,fp);
        fflush(fp);
    }
    fflush(fp);
    fclose(fp);
}

char* content_type(char* file)
{
    char extension[SMALL_BUF];
    char file_name[SMALL_BUF];
    strcpy(filename,file);
    strtok(file_name,".");
    strcpy(extension,strtok(NULL,"."));
    
if(!strcmp(extension,"html") || !strcmp(extension,"htm"))
    return "text/html";
else
    return "text/plain";
}

void send_error(FILE *fp)
{
    char protocol[] = "HTTP/1.0 400 Bad Requset\r\n";
    char server[] = "Server:Linux Web Server \r\n";
    char cnt_type[] = "Content-type:text/html\r\n\r\n";
    char content[] = "<html><head><title>NETWORK</title></head>"
            "<body><fontsize=+5><br>发生错误!查看请求文件名和请求方式!"
            "</font></body></html>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

潘多拉的面

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值