网络编程知识点总结
IP
IPv4:32位整形描述
192.168.1.102
IPv6:128位整型描述
端口
IP在网络中找到主机,端口在主机中找到接收消息的进程。
网络协议
网络分层模型
TCP协议->传输
UDP协议->传输层协议
IP协议->网络层协议
以太网帧协议->网络接口层协议
数据封装
socket编程
字节序
小端
数据的低位字节存储到内存的低位地址,数据的高位字节存储到内存的高位地址
大端
数据的低位字节存储到内存的高位地址,数据的高位字节存储到内存的低位地址
套接字通信的过程中操作的数据都是大端存储,包括;接收/发送的数据、IP地址、端口
TCP通信流程
TCP是一个面向连接的,安全的,流式传输协议,这个协议是一个传输层协议。
- 面向连接:是一个双向连接,通过三次握手完成,断开连接需要通过四次挥手完成。
- 安全:tcp通信过程中,会对发送的每一数据包都会进行校验,如果发现数据丢失, 会自动重传。
- 流式传输:发送端和接收端处理数据的速度,数据的量都可以不一致
- 在tcp的服务器端, 有两类文件描述符
- 监听的文件描述符
只需要有一个
不负责和客户端通信, 负责检测客户端的连接请求, 检测到之后调用accept就可以建立新的连接 - 通信的文件描述符
负责和建立连接的客户端通信
如果有N个客户端和服务器建立了新的连接, 通信的文件描述符就有N个,每个客户端和服务器都对应一个通信的文件描述符
服务端代码示例
#include <stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<arpa/inet.h>
int main(){
//1.创建 监听的套接字
int fd = socket(AF_INET, SOCK_STREAM, 0);
if(fd == -1){
perror("socket");
return -1;
}
//2. 绑定本地的IP port
struct sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(9999);
saddr.sin_addr.s_addr = INADDR_ANY;
int ret = bind(fd,(struct sockaddr*)&saddr, sizeof(saddr));
if(ret == -1){
perror("bind");
return -1;
}
//设置监听
ret = listen(fd, 128);
if(ret ==-1){
perror("listen");
return -1;
}
//4.阻塞并等待客户端连接
struct sockaddr_in caddr;
int addrlen = sizeof(caddr);
int cfd = accept(fd, (struct sockaddr*)&caddr, (socklen_t*)&addrlen);
if(cfd == -1){
perror("accept");
return -1;
}
//连接建立成功,打印客户端的IP和端口信息
char ip[32];
printf("客户端的IP:%s, 端口:%d\n", inet_ntop(AF_INET,&caddr.sin_addr.s_addr,ip,sizeof(ip)),ntohs(caddr.sin_port));
//5.通信
while (1)
{
//接受数据
char buff[1024];
int len = recv(cfd, buff,sizeof(buff),0);
if(len>0){
printf("client say: %s\n", buff);
send(cfd, buff,len,0);
}else if(len == 0){
printf("客户端已经断开连接...\n");
break;
}else{
perror("recv");
break;
}
}
//关闭文件描述符
close(fd);
close(cfd);
return 0;
}
客户端代码示例
#include <stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<arpa/inet.h>
int main(){
//1.创建 通信的套接字
int fd = socket(AF_INET, SOCK_STREAM, 0);
if(fd == -1){
perror("socket");
return -1;
}
//2. 连接服务器IP port
struct sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(9999);
inet_pton(AF_INET,"10.12.19.120",&saddr.sin_addr.s_addr);//将主机的小端存储转换成大端存储
int ret = connect(fd,(struct sockaddr*)&saddr,sizeof(saddr));
if(ret == -1){
perror("connect");
return -1;
}
int number = 0;
//3.通信
while (1)
{
//发送数据
char buff[1024];
sprintf(buff, "你好,hello, world, %d ...\n",number++);
send(fd, buff, strlen(buff)+1,0);
//接受数据
memset(buff, 0,sizeof(buff));
int len = recv(fd, buff,sizeof(buff),0);
if(len>0){
printf("server say: %s\n", buff);
send(fd, buff,len,0);
}else if(len == 0){
printf("服务端已经断开连接...\n");
break;
}else{
perror("recv");
break;
}
sleep(1);
}
//关闭文件描述符
close(fd);
return 0;
}