Linux网络编程复习笔记

理论知识点

TCP协议的三次握手的触发API

  • connect : 第一次握手信息
  • 第二次,第三次都是被动处理,无需调用接口
  • accept不参与三次握手,取出三次握手成功的描述符

socket描述符的合理大小

属于linux系统描述符fd的一部分:

f d ∈ [ 0 , 1 , 2 … … ] fd\in[0,1,2……] fd[0,1,2]

总之 f d > = 0 fd>=0 fd>=0

把socket状态从主动发送状态转变为被动监听状态

listen + TCP的描述符

send(sockfd, buf, 5, 0)

表示的是向文件描述符为sockfd的目的地址发送以buf为首地址,5个字节的内容

端口号的范围

unsigned short 16bit [0 , 65535]

大端模式,小端模式

条件
大端:0x12345678 低位地址 0x12
小端:0x12345678 低位地址 0x78

int空间的传递

网络序 :大端
CPU序 :大/小端

  • htonl()–“Host to Network Long” 将一个无符号长整型数值转换为网络字节序
  • ntohl()–“Network to Host Long” 将一个网络字节序转换为无符号长整型数值
  • htons()–“Host to Network Short” 将一个无符号短整型数值转换为网络字节序
  • ntohs()–“Network to Host Short” 将一个网络字节序转换为无符号短整型数值

服务器编程模型中独有的API

socketbindsendrecv

connect 客户端

listenaccept服务器

HTTP状态码:302 404

  • 2xx : 成功
  • 3xx : 特殊功能 302 重定向
  • 4xx : 客户端请求错误,服务器拒绝服务 404 not found
  • 5xx : 服务器服务异常

HTTP请求的动作包含哪些

HTTP请求组成

请求报文 = 请求行+请求头+请求数据

HTTP的9个请求动作

HTTP1.0:

  • GET:请求指定页面的信息,并返回实体主体
  • POST:向指定资源提交数据进行处理请求,数据存在请求体
  • HEAD: 类似get,但不返回具体内容,用于获取报头

HTTP1.1:

  • PUT:完整替换更新指定资源数据,没有就新增
  • DELETE:删除指定资源的数据
  • PATCH:部分更新指定资源的数据
  • OPTIONS:允许客户端查看服务器的支持的http请求方法
  • CONNECT:预留给能将连接改为管道的代理服务器
  • TRACE:追踪服务器收到的请求,用于测试或诊断

查看端口号命令

netstat

大概这样:
Linux网络编程复习笔记_第1张图片

多进程高并发服务器 fork调用的时机

接收到新连接后,单独开辟一个子进程独立处理这个新连接,也就是accept之后

UDP的通信API

socket

bind

sendto

recvfrom

DNS解析

通过gethostbyname函数即可解析

函数原型:

struct hostent *gethostbyname(const char *hostname);

通过输入域名我们可以将其解析,然后返回一个hostent的封装数据,这个数据的结构如下:

struct hostent{
     
    char *h_name;  //official name
    char **h_aliases;  //alias list
    int  h_addrtype;  //host address type
    int  h_length;  //address lenght
    char **h_addr_list;  //address list
}

这样我们就能解析域名并得到真正的IP地址

TCP/IP通信 全双工

全双工通过一个socket文件描述符允许数据从两边同时发送和接收

这边总结一下其他的知识点:

单工

单工指的是数据只能从一方传输,并不能实现双方通信

例如:电视、广播、收音机等

半双工

半双工指的是数据能从两方传输,但是同一时间数据只能在一个方向传输

例如:对讲机

全双工

全双工指的是数据可以从两个方向同时传输

例如:电话

零散知识点

  • socket不仅仅支持TCP/IP协议和本地进程间通信
  • 如果系统TCP使用了80端口,那么UDP也可以使用80端口
  • TCP在释放链接过程中会有四次挥手的过程
  • HTTP协议是应用层协议,他传输层是基于TCP协议的
  • 如果服务器不调用accept函数,那么三次握手不会失效
  • 如果两台电脑能ping通,说明两台电脑的网络层是相通的。
  • epoll性能比select性能各有所长
  • UDP编程中,需要指定对方的IP和端口号也能通信。sendto可以 send可以(connect后)
  • CPU有小端模式,也有大端模式,处理数据
  • Ctrl+C组合键实际触发的信号是 SIGINT
  • 在HTTP1.1规范中,OPTIONS动作代表允许客户端查看服务器的性能
  • sockaddr_in结构体中,sin_addr中一般使用INADDR_ANY宏代表可以接收任意本地设备的网络数据
  • inet_aton函数可以将主机字节序结构的IP地址转换为网络字节序
  • 在select结构中,FD_ISSET()宏用来判断文件描述符是否在文件集合中

如何设计高并发服务器

通过epoll多路复用实现高并发服务器

优点

  • epoll没有最大并发连接限制,上限是最大可打开文件的数目,一般这个数目和系统内存有关,但是考虑到服务器的内存一般不小,所以可以实现高并发

  • 效率有明显提升,epoll对于句柄事件的选择和selectpoll的遍历不同,epoll是事件相应的,即:句柄事件来到后,立即选择出来,复杂度为常数级别 O ( 1 ) O(1) O(1),不需要遍历,内核将句柄通过红黑树保存,所以随着句柄数目的增多,IO的效率也不会随之线性下降(只是会稍微下降一点)

  • 内存拷贝, select让内核把 FD 消息通知给用户空间的时候使用了内存拷贝的方式,开销较大,但是epoll 在这点上使用了共享内存的方式,这个内存拷贝也省略了。

实现机制

epoll的设计和实现与select完全不同。epoll通过在Linux内核中申请一个简易的文件系统,把原先的select/poll调用分成了3个部分:

  • step1:

调用epoll_create()建立一个epoll对象(在epoll文件系统中为这个句柄对象分配资源)

  • step2:

调用epoll_ctlepoll对象中添加这上万个连接的套接字

  • step3:

调用epoll_wait收集发生的事件的连接

只需要在进程启动时建立一个epoll对象,然后在需要的时候向这个epoll对象中添加或者删除连接。同时,epoll_wait的效率也非常高,因为调用epoll_wait时,并没有直接向操作系统复制这数万个连接的句柄数据,内核也不需要去遍历全部的连接。所以可以应对高并发的情况

用一个图来表明epoll处理的逻辑关系:
Linux网络编程复习笔记_第2张图片

代码知识点

初始化监听描述符 怎么做?可以不考虑出错处理

  • 创建socket
  • 填充自己信息,公布端口struct sockaddr_in selfbind
  • 改变为监听状态listen

eg:

int init_listen(){
     //初始化监听描述符
    int listen_fd;
    int ret;
    struct sockaddr_in server_addr;

    listen_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (listen_fd < 0) {
     
        fprintf(stderr, "fail to socket : %s\n", strerror(errno));
        return -1;
    }

    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(port);
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);

    ret = bind(listen_fd, (struct sockaddr *) &server_addr, sizeof(server_addr));
    if (ret < 0) {
     
        perror("fail to bind");
        return -1;
    }

    listen(listen_fd, 5);
    return listen_fd;
}

服务器如何获得三次握手的新描述符?

int listen_handler(int listen_fd) {
     
    int new_fd;
    new_fd = accept(listen_fd, NULL, NULL);
    if (new_fd < 0) {
     
        perror("fail to accept");
        return -1;
    }
    return new_fd;
}

循环读取文件,发送文件的方法?

void read_func() {
     
    char buf[1024];
	fd = open(xxxx);
	ret = read(fd, buf, sizeof(buf));
	while (ret) {
     
		if (ret < 0) {
     
			xxxx;break;
		}
		send(xxx, buf, ret);
		ret = read(fd, buf, sizeof(buf));
	}
}

大小端的检查方法

void judge()
{
     
    int i = 48;
    int* p = &i;
    char c = 0;
    c = *((char*)p);
    if (c == '0')
        printf("小端\n");
    else
        printf("大端\n");
}

参考文献

select、poll、epoll - IO模型超详解

IO模型之IO多路复用 异步IO select poll epoll 的用法

Linux下的socket编程实践(九) epoll实现高并发的原理及其使用

你可能感兴趣的:(Linux,c语言,linux,服务器,socket,网络)