美文网首页
网络编程-Socket

网络编程-Socket

作者: D_Major | 来源:发表于2020-03-21 02:54 被阅读0次
链路层以太网帧和ARP

以太网帧在首尾都要封装, 用来验证数据完整性. 其他IP报头, TCP段首, http协议头都只在头部封装.

ARP协议通过广播IP来来获得下一跳路由器的网卡地址. ARP数据报包括发送端的mac地址和IP地址, 以及接收端的mac地址和IP地址. 在发送时由于不知道接收端的mac地址, 所以填00:00:00:00:00:00, 当接收端(下一跳路由器)收到后, 发现IP地址和自己的一样, 就把自己的mac地址填充进数据报再广播传回去. 之后的每一跳路由器都对数据帧进行解封装再重新封装, 把最外层以太网帧的首尾解开, 再根据IP包中的目的IP地址选择路由表中的下一跳.

TTL: 最长生命周期, 传输的最大跳数. 当TTL减为0时, 当时的路由器就会把数据包丢弃.

MTU:maximum transmission unit,最大传输单元,由硬件规定,如以太网的MTU为1500字节。若一IP数据报大小超过相应链路的MTU的时候,主机会执行分片, 所以为了避免分片数据报大小一般不超过MTU.

MSS:maximum segment size,最大分节大小,为TCP数据包每次传输的最大数据分段大小,一般由发送端向对端TCP通知对端在每个分节中能发送的最大TCP数据。MSS值为MTU值减去IPv4 Header(20 Byte)和TCP header(20 Byte)得到, 等于1460。

TCP/UDP

TCP传输数据的路由通路是固定的, 只寻路一次, 所以稳定. UDP在每个路由器都要寻路, 所以不稳定.
TCP/UDP包含的是源端和目的端的16位端口信息, 其携带的数据可以超过以太网帧1500字节的限制, 只不过要分成多次传输; 或者链路层不使用以太网协议, 改用自定义的协议, 一次发送任意字节也行.

NAT和打洞

NAT映射: 以公网IP:端口号的形式把局域网IP映射到公网IP, 由路由器保存NAT映射表. 如浏览器的192.168.1.8:8080经过NAT映射到路由器后是公网IP:端口号, 之后再和目标网址通信.

打洞: 由于路由器会屏蔽第一次见到的陌生IP以防止攻击, 所以需要一个中转服务器(如腾讯, 其IP登录时已回传)把陌生路由器的IP登记, 这样两个陌生的路由器就可以直接通信了. 虽然路由器对第一次见到的包会丢弃, 但是会记录IP地址, 这样就算完成了打洞.

Socket网络通信

Socket绑定IP+端口号, 可以实现网络进程间通信. 其是一种借助缓冲区实现的伪文件, 可以全双工通信. Socket成对出现, 每边的一个fd对应发送和接收两个缓冲区, 从而实现双向通信.

Linux下占用存储的文件类型只有普通文件/目录/软链接, 硬链接是修改文件DEntry目录项属性得到的.

大端存储/小端存储

TCP/IP协议规定, 网络数据流应采用大端字节序, 即低地址高字节. 如0x12345678, 大端存储会在1003存78, 1002存56, 1001存34, 1000存12. 78是低地址, 却存放在了高字节处.
而x86平台默认小端存储, 1000存78, 1003存12, 即低地址低字节. 所以要做网络字节序和主机字节序的转换, l是32位长整型对应IP地址, s是16位短整型对应端口号.

"192.168.1.24"(字符串) -> 转成unsigned int -> htonl() -> 网络字节序
这种比较麻烦, 有函数可以直接把字符串ip变成网络字节序的二进制数, 如inet_pton()
"192.168.1.24" -> inet_pton(AF_INET, "192.168.1.24", &serv_addr.sin_addr.s_addr) -> serv_addr存放网络字节序IP
反过来就是inet_ntop(AF_INET, &serv_addr.sin_addr.s_addr, buf, sizeof(buf)), buf存放IP字符串, 注意serv_addr.sin_addr.s_addr是int类型, 要取地址传入做参数.

sockaddr_in结构体

该结构体有三个成员, 协议类型, 端口号和ip地址, 后两者都要注意字节序问题.
原来的sockaddr结构体虽然已经被废弃了, 但有的函数接口还在用, 需要强转成(struct sockaddr*)类型. 另外accept()和connect()也要对sockaddr_in进行转型.

struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET/AF_INET6;
addr.sin_port = htons()/ntohs();
addr.sin_addr.s_addr = htonl()/ntohl()/inet_pton()/inet_ntop()
bind(sockfd, (struct sockaddr *) &addr);
socket()函数

sockfd = socket(AF_INET, SOCK_STREAM, 0)创建sockfd.

bind()函数

bind(sockfd, &addr, sizeof(addr)将socket()返回的sockfd绑定到服务器的一个ip+端口号, 使sockfd监听通信. 客户端不用调用bind()是因为客户端端口号无所谓, 系统会自动分配.

listen()函数

listen(sockfd, 128)用于设置处于等待状态的最大客户端数量, 即最大同时建立连接数(不是保持连接数), 如三次握手队列, 默认128.

accept()函数

由服务端调用返回客户端sockfd, 所以传出参数sockaddr* addr返回的是客户端ip+端口号, 由服务器分配不用做初始化; socklen_t addrlen是传入传出参数, 在传入的时候是初始化客户端地址结构体的大小, 传出时是实际返回的客户地址结构体的大小.

socklen_t client_addr_len = sizeof(client_addr);
client_fd = accept(server_fd, &client_addr, &client_addr_len)

accept()返回的客户端sockfd用于和客户端通信, 和前面socket()创建的服务端sockfd不是同一个. 无客户端请求时, 服务端阻塞直到有客户端连接.

connect()函数

connect(sockfd, &addr, sizeof(addr))由客户端调用, addr是服务端的ip和端口号, 需要已创建一个sockfd. 不同于bind()用于监听自身端口, connect()是向服务器发起连接.
由于client.c和server.c并不是一个线程, 所以分配的sockfd没有关联性, sockfd只是连接两个端口的中介, 而不是一个真正的文件.

netstat -apn | grep 6666查看端口号占用情况, 需要先终止client后终止server, 否则端口号无法释放.

封装函数和系统函数同名的好处是可以进入帮助文档, 如socket()和Socket(), 首字母大小写不同不影响进入帮助文档, 但是可以封装错误处理之类的信息, 使代码更简洁. 其参数列和返回值必须和系统函数完全一样.

应该实现一个readn()和writen()函数, 每次从socket读写n个字节, 因为可能一个以太网帧1500个字节装不下要分多次传进来, 这时普通的read()会直接返回. 形如readn(cfd, buf, n), 每次读完后n-=1500(N-nread=nleft), 同时ptr+=1500, buf的一部分空间. 一般可以用来获取http头部信息.
另外, 读socket无法用fgets(), 需要再实现一个Readline()函数.

相关文章

  • 许世伟的Go语言基础 第五章总结

    第5章 网络编程 5.1 socket编程 以往socket编程: 建立socket:使用socket()函数。 ...

  • 网络编程

    python学习笔记-网络编程 socket编程: socket()函数:socket.socket([famil...

  • 网络编程

    网络 Socket 基于TCP协议的Socket编程 基于UDP协议的Socket编程

  • 2018-09-12 day18-网络编程和http请求

    网络编程 socket 网络编程就是socket编程,socket就是套接字,就是进行数据通信的两端(服务器和客户...

  • 网络基础介绍

    网络编程的两种 TCP socket编程,是网络编程的主流。之所以叫Tcp socket编程,是因为底层是基于Tc...

  • Go语言的Socket编程

    我们在日常开发当中,几乎所有网络编程都是Socket编程,因为大部分底层网络的编程都离不开Socket编程。 什么...

  • 动脑学院架构篇-Java Socket编程基础及深入讲解

    【Socket】Java Socket编程基础及深入讲解 Socket是Java网络编程的基础,了解还是有好处的,...

  • Python网络编程

    Python网络编程 1、socket编程, 类:socket 1.server端 # socket第一个参数:地...

  • TCP通信网络编程

    1. Socket网络编程 Socket是网络编程的一个抽象概念。通常我们用一个Socket表示“打开了一个网络链...

  • Netty

    一、网络编程基础原理 1 网络编程(Socket)概念 首先注意,Socket不是Java中独有的概念,而是一个语...

网友评论

      本文标题:网络编程-Socket

      本文链接:https://www.haomeiwen.com/subject/dfdaehtx.html