目录
一,源ip和目的ip
在我们的电脑中,会有一个ip地址。如果没有这个ip地址我们便无法上网。那ip地址是什么呢?其实ip地址就是一串点分十进制的一串字符串,这串字符串能够标识全网唯一的一台主机。所以这就注定了当我们的主机要通过网络通信时必须要有源ip和目的ip包含在报头里面,这样才能指明这个我们的消息从哪里发出又要到那里去。
但是,我们的网络通信的本质其实是进程间通信。我们也都知道一台主机上的进程是有很多的,那我们如何来标识唯一的进程呢?
二,端口号port
1,端口号的作用和特点
在计算机中,端口号可以表示计算机中唯一的一个进程。
端口号:
1,一个端口号由两个字节16位的整数表示。
2,一个端口号只能被一个进程绑定。3,端口号标识一个进程,它能够告诉操作系统应该将数据交给那一个进程。
2,为什么不用pid标识?
学过系统的同学们都知道,在进程的pcb当中有一个字段叫做pid,这个pid便能够标识系统中唯一的一个进程。那为什么在网络通信中不用pid标识唯一的一个进程呢?而要用一个全新的概念----端口号来标识呢?
原因:
1,pid是系统中的概念,不同的系统会有不同的pid表示方式,不利于网络通信的跨平台实现。
2,有些端口号是不能被使用的,使用pid可能会访问这些特殊的端口号进而导致通信错误。
三,UDP/TCP协议
当我们要传输数据时,传输层是我们绕不过的坎。所以我们必须要遵守传输层的协议。
在传输层,协议分为两类: UDP协议和TCP协议。
这两个协议的特点如下:
UDP:
1,无连接。
2,不可靠。
3,面向数据报。
TCP:
1,有连接。
2,可靠。
3,面向字节流。
关于可靠和不可靠:
在这里要澄清一下,在计算机的世界里,可靠和不可靠其实是一对中性词。可不可靠其实是基于TCP和UDP协议对于数据丢失是否有对应的措施,TCP有,UDP没有。防丢失措施的实现必然要付出代价,所以按照TCP实现网络通信就会比较复杂,UDP通信虽然不可靠,但是实现起来就会比较的简单。
四,网络字节序
计算机,分为大端机和小端机。因为这个原因,两台不同的计算机在通过网络通信时可能会发生数据传输和解析错误的情况。所以,在计算机当中就出现了网络字节序来统一大端机和小端机。
网络字节序:
1,保证两台主机能够正确的接收和传输数据。
2,小端字节序转为大端字节序,大端字节序不用转。
五,socket
1,sockt理解
sockt翻译过来便是“插头,插座。在计算机当中,sicket其实被称为套接字。而套接字其实就是ip+port。所以,通过套接字便可以找到全网当中唯一的一个进程。
2,socket网络编程
在计算机中,便有通过socket套接字网络编程。这种编程技术便是通过套接字找到全网中唯一的两个进程,然后通过网络这个共享资源来完成通信的技术。
3,socket套接字编程常用API
1,创建socket套接字
int socket(int domain, int type, int protocol);
domain:创建套接字的域/协议家族
本地:ATF_UNIT
网络:AF_INET(IPV4) ,AF_INET6(IPV6)
type:服务类型
数据报式套接字:SOCK_DGRAM(用于udp服务)
流式套接字:SOCK_STREAM(用于tcp服务)
protocol:套接字协议
一般设置为0
也可以明确的设置为TCP/UDP
2,绑定ip和port
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
sockaddr:
sockaddr是一个常用的套接字结构体,用于表示套接字的地址。
struct sockaddr { sa_family_t sa_family; char sa_data[14]; }
示意图:
但是,这个结构体通常会以更加具体的方式体现。当你要表示网络套接字地址时就可以换成sockaddr_in
当你要表示本机的地址时便可以使用sockaddr_un:
但是不论是什么网络还是本地的地址,都可以转化为sockaddr*的形式,这种实现方式就相当于C++中的多态。
3,端口号转化API
要将端口号转化为网络序列:h代表host,n代表net
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
4,ip转化API
将字符型转为整型:in_addr_t inet_addr(const char *cp)
将整型转为字符型:char *inet_ntoa(struct in_addr in)
5,接收数据报消息
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);
sockfd:套接字
buf:接收信息的缓冲区
len:缓冲区大小
flags:接收消息的方式
src_addr:自己定义的sockaddr结构体,不需要初始化是一个输出型参数,为了得到send消息的主机的ip地址和端口号
addrlen:倒数第二个参数的长度
6,发送消息
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen)
sockfd:套接字
buf:存放消息的缓冲区
len:缓冲区大小
flags:接收消息的方式
dest_addr:自己初始化的sockaddr结构体
addrlen:倒数第二个参数的长度