您现在的位置是:首页 >技术交流 >socket套接字通信 TCP传输控制协议/IP网络协议 5.18网站首页技术交流
socket套接字通信 TCP传输控制协议/IP网络协议 5.18
B/S :浏览器和服务器
C/S :客户机和服务器
网络的体系结构:
网络的层次结构和每层所使用协议的集合
网络采用分层管理的方法,将网络的功能划分为不同的模块
OSI模型:
共7种:
应用层:接收用户的数据,面向的应用程序
表示层:逻辑语言转为机器语言,翻译,加密
会话层:针对传输的每一种数据建立一条虚连接
高层
传输层:作用 1.区分流量 2.定义数据传输方式
网络层:network 编址 寻址
数据链路层:数据链路层分为LLC层(逻辑链路控制子层)和MAC层(介质访问控制子层)
二层地址:MAC地址(介质访问控制)- -物理/硬件/烧录地址
物理层:传输介质(有线、无线)
地层
TCP/IP协议:传输控制协议 / 网络协议
用户模式
应用层:使用相应的协议,将封装好的数据提交给传输层,或是传输层接收数据并处理。 FTP头信息
内核模式:
传输层:负责实现应用程序之间的通信服务,又称端对端通信 TCP头信息
网络层:负责主机间的通信,传输数据包 IP头信息
网络接口层:将二进制转化为数据帧,并进行数据帧的发送和接受
数据的封装与传递过程:
网络传输数据大小user data: 6~1460
网络传输中容易发生拆包和粘包,所以接收和发送的字节数要对齐,否则容易传输不上
TCP和UDP协议
共同点:传输层,全双工的
不同点:TCP有连接可靠的,UDP无连接不可靠数据容易丢
TCP
是一种面向连接的传输层协议,它能提供高可靠性通信(即数据无误、数据无丢失、数据无失序、数据无重复到达的通信)
传输质量较高,输出大量数据
传输需要账号,一对一
传输数据时较慢
UDP
(User Datagram Protocol)用户数据报协议,是不可靠的无连接的协议。在数据发送前,因为不需要进行连接,所以可以进行高效率的数据传输。
发送小尺寸数据,无线网络
广播/组播式通信中,一对多
实时性较高
传输数据时快,资源消耗小
网络编程
1.预备知识
1)socket套接字
网络编程的通用接口
是一种特殊的文件描述符
当调用socket函数时就会创建一个套接字,并返回套接字的文件描述符
支持面向连接(TCP)与无连接(UDP)
套接字的类型
TCP所用的时流式套接字,用于可靠传输,SOCK_STREAM
UDP所用的数据报套接字,用于无连接不可靠的,SOCK_DGRAM
SOCK_RAW:原始套接字,直接作用于网络层
套接字位于应用层与传输层之间,OSI模型的会话层和传输层之间
2)IP地址
IP地址就是网络中主机的标识—区分不同的主机
IP地址:IPv4(32)和IPv6(128)
IP地址表示:点分形式;例:192.168.2.99
IP地址 = 网络号 + 主机号
网络号:IP & 子网掩码
主机号:IP & (-子网掩码)
同一局域网内主机号,网络号相同,主机号不同
Linux:
ifconfig : 查看IP地址
ifconfig ens33 up/down/IP … 启动/关闭/设置IP
ping IP/域名 : 检测网络是否联通
6、解决有线无无法边接:显示Wired Unmanaged
{
dashhome/system setting/network。显示Wired Unmanaged
解决方法:
sudo vim /etc/NetworkManager/NetworkManager.conf
将managed=false
改成managed=true
然后重启network-manager
sudo service network-manager restart
或者 kill掉再启用:sudo NetworkManager。再不行就重启:sudo reboot
}
IP地址的转换
inet_aton()
字符串->网络字节序
将strptr所指的字符串转换成32位的网络字节序二进制值
#include <arpa/inet.h>
int inet_aton(const char *strptr,struct in_addr *addrptr);
inet_addr()
字符串->网络字节序并且返回地址
功能同上,返回转换后的地址。
in_addr_t inet_addr(const char *strptr);
inet_ntoa()
网络字节序->字符串
将32位网络字节序二进制地址转换成点分十进制的字符串。
char *inet_ntoa(stuct in_addr inaddr);
3)端口号
同一台主机上区分不同任务的标识
一台主机接收到的数据包应该转交给哪个任务来处理
类型:unsigned short (1~65536)
保留端口 1~1023
系统分配端口 1024~5000
自己分配端口 5001~65536
4)字节序(大小端)
小端存储:低字节数据存在低地址,高字节数据存储在高地址
先存fd
大端存储:低字节数据存在高地址,高字节数据存储在低地址
先存fa
unsigned int a = 0xfafbfcfd
fa高字节数据
fd低字节数据
/*===============================================
* 文件名称:zijiexu.c
* 创 建 者:memories
* 创建日期:2023年05月18日
* 描 述:
================================================*/
地址由低到高存储,如果存的是fd则是小段存储
#include <stdio.h>
int main(int argc, char *argv[])
{
unsigned int a = 0xfafbfcfd;
unsigned char *p = (unsigned char*)&a;
printf("*p=%x
",*p);//%x表示十六进制
return 0;
}
hqyj@ubuntu:~/5.18$ gcc zijiexu.c
hqyj@ubuntu:~/5.18$ ./a.out
*p=fd
网络传输统统使用大端序,所以大端序也称为网络字节序
主机一般使用小端序,所以小端序也称为主机字节序
网络字节序和主机字节序的转换
主机字节序到网络字节序
u_long htonl (u_long hostlong);
u_short htons (u_short short);
网络字节序到主机字节序
u_long ntohl (u_long hostlong);
u_short ntohs (u_short short);
2.TCP网络编程框架
类似于app是客户端,app中的内容是服务器提供的
***服务器(server)流程***
socket ---- 创建套接字,两者都要创建
bind ---- 绑定本机地址和端口
listen ---- 设定监听套接字,检测是否有客户端访问服务器
accept ---- 接收客户端的连接,并生成通信套接字
read/write() ---- 接收/发送数据
close() ---- 关闭套接字
-----------------------------------------------------
***客户端:client***
socket ---- 创建套接字,两者都要创建
connect ---- 主动连接服务器
write/read() ---- 发送/接收数据
close() ---- 关闭套接字
3.网络编程接口
1)socket()
作用:创建套接字
函数:
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
参数:
domain:地址族:AF_INET:IPv4 internel protocol
type:套接字类型
SOCK_STREAM:流式套接字 TCP
SOCK_DGRAM:数据报套接字 UDP
protocol:0
返回值:
成功:套接字文件描述符
失败:-1,并设置error
2)bind()
作用:绑定本机地址和端口
函数:
#include <sys/types.h>
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
参数:
sockfd:套接字文件描述符
addr:地址结构体
addrlen:地址长度
返回值:
成功:0
失败:-1,并设置error
地址结构:
struct sockaddr { //通用地址
sa_family_t sa_family;
char sa_data[14];
}
struct sockaddr_in { //IPv4地址结构
sa_family_t sin_family; /* address family: AF_INET */
in_port_t sin_port; /* port in network byte order */
struct in_addr sin_addr; /* internet address */
};
/* Internet address. */
struct in_addr { //网络字节序
uint32_t s_addr; /* address in network byte order */
};
例如:
//用IPv4结构体
struct sockaddr_in srvaddr;
memset(&srvaddr,0,sizeof(srvaddr));
srvaddr.sin_family = AF_INET;//指定地址族为IPv4的地址
srvaddr.sin_port = htons(6666);//端口号
srvaddr.sin_addr.s_addr = inet_addr("192.168.2.84");//将点分式的字符串转化32位的网络字节序
bind(sockfd,(struct sockaddr*)&srvaddr,sizeof(srvaddr));
3)listen
作用:设置监听套接字
函数:
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int listen(int sockfd, int backlog);
参数:
sockfd:套接字描述符
backlog:监听队列长度(>0)
返回值:
成功:0
失败:-1,并设置error
4)accept()
作用:接收客户端的连接,并生成通信套接字
函数:
#include <sys/types.h> /* See NOTES */ #include <sys/so
cket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
参数:
sockfd:套接字文件描述符
addr:客户端地址结构体
addrlen:客户端地址长度
当不需要知道连接的客户端是谁时,第2,3参数都可以设置NULL
返回值:
成功:连接成功的通信套接字
失败:-1,并设置error
服务器套接字:
监听套接字(普通套接字转为监听套接字):用于监听、连接
通信套接字:用于通信(发送、接收)
/*===============================================
* 文件名称:server.c
* 创 建 者:memories
* 创建日期:2023年05月18日
* 描 述:
================================================*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
//1.创建套接字
int sockfd = socket(AF_INET,SOCK_STREAM,0);
if(sockfd<0)
{
perror("socket");
return -1;
}
printf("socket-----------------
");
//2.绑定本机地址和端口
//用IPv4结构体
struct sockaddr_in srvaddr;
memset(&srvaddr,0,sizeof(srvaddr));
srvaddr.sin_family = AF_INET;//指定地址族为IPv4的地址
srvaddr.sin_port = htons(5429);//端口号
srvaddr.sin_addr.s_addr = inet_addr("192.168.2.84");//将点分式的字符串转化32位的网络字节序
if(0 > bind(sockfd,(struct sockaddr*)&srvaddr,sizeof(srvaddr)))
{
perror("bind");
return -1;
}
printf("bind-----------------
");
//3.设置监听套接字
if(0>listen(sockfd,5))//必须写大于1的整数
{
perror("listen");
return -1;
}
printf("listen-----------------
");
//4.接受客户端的连接,并生成通信套接字
int connfd = accept(sockfd,NULL,NULL);
if(connfd < 0)
{
perror("accept");
return -1;
}
printf("accept-----------------
");
//5.与客户端通信
int ret;
char buf[1024];
while(1)
{
memset(buf,0,sizeof(buf));
ret = read(connfd,buf,sizeof(buf));
if(ret < 0)
{
perror("read");
break;
}
else if(ret == 0)
{
printf("write close
");
break;
}
printf("recv:%s
",buf);
if(0 > write(connfd,buf,ret))
{
perror("write");
return -1;
}
}
//6.关闭套接字
close(sockfd);
close(connfd);
return 0;
}
/*===============================================
* 文件名称:client.c
* 创 建 者:memories
* 创建日期:2023年05月18日
* 描 述:
================================================*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
int main(int argc, char *argv[])
{
//1.创建套接字
int sockfd = socket(AF_INET,SOCK_STREAM,0);
if(sockfd<0)
{
perror("socket");
return -1;
}
printf("sockfd:%d
",sockfd);
printf("socket------------
");
//2.主动连接服务器
struct sockaddr_in sockst;
sockst.sin_family = AF_INET;
sockst.sin_port = htons(5429);
sockst.sin_addr.s_addr = inet_addr("192.168.2.84");
int conn = connect(sockfd,(struct sockaddr*)&sockst,sizeof(sockst));
if(conn <0)
{
perror("connect");
return -1;
}
while(1)
{
char buf[1024]={0};
fgets(buf,sizeof(buf),stdin);
write(sockfd,buf,strlen(buf));
if(strncmp(buf,"quit",4)==0)
{
break;
}
}
//3.关闭套接字通信
close(sockfd);
return 0;
}
hqyj@ubuntu:~/5.18$ gcc client.c
hqyj@ubuntu:~/5.18$ ./a.out
sockfd:3
socket------------
你好
?
hqyj@ubuntu:~/5.18$ gcc server.c
hqyj@ubuntu:~/5.18$ ./a.out
socket-----------------
bind-----------------
listen-----------------
accept-----------------
recv:你好
recv:?