TCP/IP 协议族:常用协议
物理链路层: ARP RARP MTU
网络层: IP ICMP RIP OSPF IGMP ?
传输层: TCP UDP
应用层: TFTP HTTP HTTPS SNMP SMTP DNS
TCP 协议 ===》RFC 793
TCP 传输控制协议: 有链接 可靠 实时
UDP 协议 ===》RFC 768
UDP 用户数据报协议: 无链接 不可靠 不实时
网络地址划分:
A类网络:第一组表示网络,后面三组表示主机:
二进制最高位必须是0开头 ,0xxxxxxx
十进制表示范围:1.0.0.0~126.0.0.0 127.0.0.0 是回环诊断用
默认掩码: 255.0.0.0
网络数:126个 每个子网主机数:1亿多
注意: 127.0.0.1 ===》本机的回还地址
10.0.0.0 ===》10.255.25.255 A类网络的私有地址不会在互联网出现。
B类网络:前两组表示网络,后两组表示主机;
二进制最高位必须是10开头,10xxxxxx
十进制表示范围:128.0.0.0~191.255.255.255
默认掩码: 255.255.0.0
网络数:16382个,每个子网主机数6万多
互联网上不会出现的私有地址:
172.16.x.x
169.254.x.x
C类网络:前三组表示网络,后一组表示主机
二进制最高位必须是110开头,110xxxxx
十进制表示范围:192.0.0.0~223.255.255.255
默认掩码: 255.255.255.0
网络数:209万多个,每个子网主机数 254个
私有地址:
192.168.x.x 局域网内部测试使用。
D类网络:二进制最高位必须是1110开头,1110xxxx
十进制表示范围:224.0.0.0~239.255.255.255
没有掩码
多点广播地址范围。
上网的流程:
0、物理链路链接正常。
1、liunux : 配置ip地址 ==》ifconfig ethX x.x.x.x/24 up
配置网关 ===>route -n ==>route add default x.x.x.x
检测链路: ping 8.8.8.8 ping 61.134.1.4
配置DNS: vi /etc/resolv.conf ==>DNS 8.8.8.8
2、WINDOWS: 配置ip地址: 网络 ==》更该适配器设置==》以太网右键
==》属性====》TCP/IPv4 ===》属性
配置:ip地址
dns地址
============================================================
网络系统调用接口
1、socket ====>BSD socket ==>套接字
分类:SOCK_STREAM 基于TCP协议的套接字 流式套接字
SOCK_DGRAM 基于UDP协议的套接字 用户数据报套接字
SOCK_RAW 原始套接字
2、IP+port
ip IP地址 有(A,B,C,...)类
port 应用程序对外的数字编号 范围如下
TCP PORT 1-65535
UDP PORT 1-65535
3、字节序
大端存储 ===》数据的低端 === 内存的高端
小端存储 ===》数据的低端 === 内存的低端
头文件: #include <arpa/inet.h>
数字:
主机转网络字节序: htonl
htons
网络转主机字节序: ntohl
ntons
字符串:
主机转网络字节序:inet_addr()
网路转主机字节序:inet_ntoa()
网络编程之 TCP 编程 ==》C/S 模式
C: 客户端 ==》流程:
socket()==>bind(可选)===>connect()==>send()/recv() ===>close()
S: 服务器端
socket()==>bind()==>listen()==>accept()==>recv()/send() ==>close()
函数:
头文件
#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
功能:通过该函数可以创建一个套接字通信文件。
参数:domain 地址族: PF_INET(AF_INET) PF_UNIX(AF_UNIX)
type 套接字类型:
SOCK_STREAM SOCK_DGRAM SOCK_RAW
protocol 0 表示有os自动匹配合适的协议。
返回值:成功 返回套接字 id >0 的数字。相当与一个文件描述符。
失败 -1;
int connect(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
功能:该函数只能用于客户端链接服务器端使用。表示从本地创建
的sockfd中发起链接到addr指向的服务器地址。
参数:sockfd 之前通过socket创建的套接字。
addr 要链接的服务器地址。
addrlen 要链接的服务器地址的长度。
返回值:成功 0
失败 -1;
注意:struct sockaddr的类型如下:
通用地址类型
struct sockaddr
{
u_short sa_family; 协议族类型
char sa_data[14]; 14字节的地址信息
};
转换后的网络地址类型:
struct sockaddr_in
{
u_short sin_family;
u_short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
}
struct in_addr
{
in_addr_t s_addr; 网络字节序的IP地址
}
要用该类型必须注意字节序转换:
发送/接受数据:
三组六对:
send()/recv() ===>TCP
sendto()/recvfrom() ===>UDP
write()/read ===>IP
int send(int sockfd, const void *msg, size_t len, int flags);
功能:从msg所在的内存中取出len长度的数据写入到sockfd的套接字中。
参数: sockfd 要发送数据的套接子id
msg 要发送的数据的来源
len 要发送的数据长度
flags 发送数据的方式 0 表示阻塞方式发送。
MSG_DONTWAIT 表示非阻塞方式发送。
返回值:成功 发送数据长度
失败 -1
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
功能:从指定的sockfd套接子中获取长度为len的数据到buf内存中。
参数:sockfd 要获取数据的套接字id
buff 要存储数据的本地内存
len 要存储的数据长度,一般等于buff的大小。
flags 接收方式,0 表示阻塞方式接受
返回值:成功 表示接受的数据长度,一般小于等于len
失败 -1;
关闭:
int close(int fd);
功能:关闭已经使用完毕的套接字id
参数:套接字id
返回值:成功 0
失败 -1;
服务器端:
socket()==>bind()===>listen()===>accept()===>recv()/send()===>close()
原型:int bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen);
参数:sockfd 之前通过socket创建的套接字id
my_addr 要bind的本地接口地址。
addr 要bind的地址长度。
返回值:成功 0
失败 -1;
注意:该函数的参数2 应该如下设置:
1、先定义本地地址变量:struct sockaddr_in myaddr;
2、给本地变量赋值:
myaddr.sin_family = PF_INET;
myaddr.sin_port = htons(8888);
myaddr.sin_addr.s_addr = inet_addr("192.168.0.100");
socklen_t len = sizeof(myaddr);
3、用该变量来bind到套接字:
bind(sockfd,(struct sockaddr *)&myaddr,len);
int listen(int sockfd, int backlog);
功能:从sockfd对应的套接字中监控链接。
参数:sockfd 要监控的套机字id
backlog 允许同时链接的客户端个数。
返回值:成功 0
失败 -1;
原型:int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
功能:该函数有服务器端执行并将新链接接收入当前进程。
参数:sockfd要获取链接的本地套接字id
addr 获取的客户端信息结构体。
如果不关心客户端信息,则该值为NULL;
如果要获取信息,则需要事先定义变量并传入地址。
addrlen 参数3的长度的指针:
socklen_t len = sizoef(addr); &len;
返回值:成功 返回一个新的套接字id用于以后的通信过程。
失败 -1;
注意:该函数执行完毕,则后面的send recv 的参数1 都用该函数返回值。
问题:
1、connect : No route to host
解决: service iptables stop
2、bind: Address already in use
解决: int on = 1; ///将以下语句加在bind函数之前
setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on))
细节:
1、要获取客户端的信息:accept(sockfd,cliaddr,&len)
的参数2 3 必须设置。
2、要使客户端从指定的端口发送数据。
在客户端用 bind 函数
练习:
通过TCP程序发送一个结构体信息,在另一端将该结构体成员
变量的值都打印出来。
假设结构如下:
typedef struct
{
int id;
char name[32];
char pass[64];
}STU;
作业:
通过以上函数的学习,尝试完成如下功能:
客户端可以给服务器发送一个指定的文件。
服务器收到该文件并存储到指定位置。
要求:尽量把文件的名称发过去。服务器要
用同名文件存储。