TCP协议分成了两个不同的协议: 用来检测网络传输中差错的传输控制协议TCP 专门负责对不同网络进行互联的互联网协议IP 从此,TCP/IP协议诞生 1983年ARPAnet上停止使用NCP,互联网上的主机全部使用TCP/IP协议。TCP/IP协议成为Internet中的“世界语”
网络采用分而治之的方法设计,将网络的功能划分为不同的模块,以分层的形式有机组合在一起。 每层实现不同的功能,其内部实现方法对外部其他层次来说是透明的。每层向上层提供服务,同时使用下层提供的服务 网络体系结构即指网络的层次结构和每层所使用协议的集合 两类非常重要的体系结构:OSI与TCP/IP
OSI模型相关的协议已经很少使用,但模型本身非常通用 OSI模型是一个理想化的模型,尚未有完整的实现 OSI模型共有七层
TCP/IP协议是Internet事实上的工业标准。 一共有四层
OSI模型与TCP/IP协议
TCP/IP分层
通信协议模型
数据的封装与传递
TCP(即传输控制协议)
打电话 是一种面向连接的传输层协议,它能提供高可靠性通信(即数据无误、数据无丢失、数据无失序、数据无重复到达的通信) 适用情况: 适合于对传输质量要求较高,以及传输大量数据的通信。 在需要可靠数据传输的场合,通常使用TCP协议 MSN/QQ等即时通讯软件的用户登录账户管理相关的功能通常采用TCP协议
UDP(User Datagram Protocol)
用户数据报协议 是不可靠的无连接的协议。在数据发送前,因为不需要进行连接,所以可以进行高效率的数据传输。寄信 适用情况: 发送小尺寸数据(如对DNS服务器进行IP地址查询时) 在接收到数据,给出应答较困难的网络中使用UDP。(如:无线网络) 适合于广播/组播式通信中。 MSN/QQ/Skype等即时通讯软件的点对点文本通讯以及音视频通讯通常采用UDP协议 流媒体、VOD、VoIP、IPTV等网络多媒体服务中通常采用UDP方式进行实时数据传输
编程相关知识:
socket
Socket 是一个编程接口 是一种特殊的文件描述符 (everything in Unix is a file) 并不仅限于TCP/IP协议 面向连接 (Transmission Control Protocol - TCP/IP) 无连接 (User Datagram Protocol -UDP 和 Inter-network Packet Exchange - IPX)
流式套接字(SOCK_STREAM)
提供了一个面向连接、可靠的数据传输服务,数据无差错、无重复的发送且按发送顺序接收。内设置流量控制,避免数据流淹没慢的接收方。数据被看作是字节流,无长度限制。
数据报套接字(SOCK_DGRAM)
提供无连接服务。数据包以独立数据包的形式被发送,不提供无差错保证,数据可能丢失或重复,顺序发送,可能乱序接收。
原始套接字(SOCK_RAW)
可以对较低层次协议如IP、ICMP直接访问。
IP地址
Internet中主机的标识 Internet中的主机要与别的机器通信必须具有一个IP地址 IP地址为32位(IPv4)或者128位(IPv6) 每个数据包都必须携带目的IP地址和源IP地址,路由器依靠此信息为数据包选择路由
端口号
为了区分一台主机接收到的数据包应该转交给哪个进程来进行处理,使用端口号来区别 TCP端口号与UDP端口号独立
端口号一般由IANA (Internet Assigned Numbers Authority) 管理
众所周知端口:1~1023(1~255之间为众所周知端口,256~1023端口通常由UNIX系统占用)
注册端口:1024~49150
动态或私有端口:49151~65535
字节序
不同类型CPU的主机中,内存存储多字节整数序列有两种方法,称为主机字节序(HBO): 小端序(little-endian) 低序字节存储在低地址将低字节存储在起始地址,称为“Little-Endian”字节序,Intel、AMD等采用的是这种方式; 大端序(big-endian) 高序字节存储在低地址
关于socke的API函数详解在另外一篇博客里写了: https://blog.csdn.net/weixin_38452632
TCP:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <arpa/inet.h>
int main(int argc, char **argv)
{
// 创建一个TCP套接字
int fd = socket(AF_INET, SOCK_STREAM, 0);
if(fd == -1)
{
perror("socket failed");
exit(0);
}
// 搞一个IPv4的地址结构体,并正确赋值
struct sockaddr_in addr;
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
inet_pton(AF_INET, "192.168.7.3", (void *)&addr.sin_addr);
addr.sin_port = htons(50001);
// 绑定号码
bind(fd, (struct sockaddr *)&addr, sizeof(addr));
// 设置监听状态
// 3+4代表以后的最大同时链接请求个数
listen(fd, 3);
// 默默等待对方的链接请求
// fd: 监听套接字
// connfd: 读写套接字
int connfd = accept(fd, NULL, NULL);
char msg[100];
while(1)
{
bzero(msg, 100);
if (0 == read(connfd, msg, 100))
break;
printf("Jack: %s", msg);
}
close(fd);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <arpa/inet.h>
int main(int argc, char **argv) // ./Jack 192.168.7.200 50001
{
// 创建一个TCP套接字
int fd = socket(AF_INET, SOCK_STREAM, 0);
if(fd == -1)
{
perror("socket failed");
exit(0);
}
// 搞一个IPv4的地址结构体,并赋值为服务端的地址
struct sockaddr_in srvaddr;
bzero(&srvaddr, sizeof(srvaddr));
srvaddr.sin_family = AF_INET;
inet_pton(AF_INET, argv[1], (void *)&srvaddr.sin_addr);
srvaddr.sin_port = htons(atoi(argv[2]));
// 链接对方
connect(fd, (struct sockaddr *)&srvaddr, sizeof(srvaddr));
char msg[100];
while(1)
{
bzero(msg, 100);
fgets(msg, 100, stdin);
if (0 == write(fd, msg, strlen(msg)))
break;
}
close(fd);
return 0;
}
UDP:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <arpa/inet.h>
int main(int argc, char **argv)
{
// 创建一个UDP套接字
int fd = socket(PF_INET, SOCK_DGRAM, 0);
if(fd == -1)
{
perror("socket failed");
exit(0);
}
// 搞一个IPv4的地址结构体,并正确赋值
struct sockaddr_in addr;
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(50001);
// 绑定号码
bind(fd, (struct sockaddr *)&addr, sizeof(addr));
char msg[100];
while(1)
{
bzero(msg, 100);
recvfrom(fd, msg, 100, 0, NULL, NULL);
printf("Jack: %s", msg);
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <arpa/inet.h>
int main(int argc, char **argv) // ./Jack 192.168.7.200 50001
{
// 创建一个UPP套接字
int fd = socket(AF_INET, SOCK_DGRAM, 0);
if(fd == -1)
{
perror("socket failed");
exit(0);
}
// 搞一个IPv4的地址结构体,并赋值为服务端的地址
struct sockaddr_in srvaddr;
bzero(&srvaddr, sizeof(srvaddr));
srvaddr.sin_family = AF_INET;
inet_pton(AF_INET, argv[1], (void *)&srvaddr.sin_addr);
srvaddr.sin_port = htons(atoi(argv[2]));
char msg[100];
while(1)
{
bzero(msg, 100);
fgets(msg, 100, stdin);
sendto(fd, msg, strlen(msg), 0,
(struct sockaddr *)&srvaddr, sizeof(srvaddr));
}
return 0;
}