当前位置: 首页 > news >正文

TCP day39

六:C/S和B/S端

C/S:Client, server
B/S:Browser server

1.cs 专用客户端 bs 通用客户端
2.协议不同
Cs 标准协议,自定义协议
Bs http 超文本传输
3.cs 功能复杂 bs 功能弱
4.bs 资源都在ser,有ser发送到cli
cs 大部分资源都在cli

七:UDP和TCP特性

UDP:

  1. 无连接
    不需要维护繁杂网络状态。网络开销小。通信双方通信过程,无法知道对方进程关闭。如果需要告知,需要发信息通知。
  2. 不可靠,
    传输数据的过程中,会有丢包。但是实时性好。适用直播 视频传输,音频传输。
    3.很容易实现一对多 。
    4.可以组播,广播

TCP:

1.有链接,一次会话中,链接一直保持。如果一个断开,另外一方可以感知
2.可靠 。靠机制保障。应答超时重传

八:流式套接字

流式套接字 是一种tcp socket 队列
1.有顺序,连续
2.发送和接收的次数不需要对应。
3.send 发送快,写阻塞

流式套接字 是一种tcp socket 队列
1.有顺序,连续
2.发送和接收的次数不需要对应。
3.send 发送快,写阻塞

流式套接字 是一种tcp socket 队列
1.有顺序,连续
2.发送和接收的次数不需要对应。
3.send 发送快,写阻塞

  1. 数据之间没有边界

数据没有边界会导致数据的黏包
接收收到数据后,无法正常解析

解决方法1.协商边界
2.固定大小
3.自定义协议

//3.
eg:		AA       03      1 2 3        crc     BB开始    长度     数据      校验      结束//都是自己定义的形式

九:TCP服务器和客户端函数流程

服务器
socket(); 打开网络设备 获得文件描述符(套接字) listfd 监听套接字,作用,就是三次握手
bind();// 给套接字设定ip(确定主机)+port(对应到进程pid)
listen(); 使监听套集字进入监听状态(可以被三次握手的状态)
accept();// 服务器和客户端进入三次握手阶段,并建立连接。并获得通信套接字(服务器和客户端后续进行通信,用的套接字)
recv() ;;//阻塞接收客户端的数据。 0 ==ret 代表对方断开连接。-1 ,代表错误。 >0 实际接收到的字节数。
send();//发送的数据。 发送过程中有可能阻塞。发送的快,把对方的缓冲区填满就阻塞。
close().当收到对方的断开请求(0 == recv())。就断开与客户端的通信。
客户端
socket(); 打开网络设备 获得文件描述符(套接字) ,通信套接字
connect();客户端主动连接服务器 。触发三次握手。
send() ;//发送的数据。 发送过程中有可能阻塞。发送的快,把对方的缓冲区填满就阻塞。
recv();//阻塞接收客户端的数据。 0 ==ret 代表对方断开连接。-1 ,代表错误。 >0 实际接收到的字节数。
close(); 当客户端请求服务完成后,主动关闭套接字。触发四次挥手。

9.1:三次握手/四次挥手
三次握手
c->syn(请求连接), c_num(起始发送数据的编号)   -> s 
s->syn,ACK(应答)S_num(起始发送数据的编号)->c 
c -> ACK  ->s 四次挥手
c->FIN(断开连接)->ACK-> s 
s->ACK (应答上次fin的请求)->c 
s-> FIN(断开连接) +ACK (应答上次fin的请求)->c 
c -> ACK(s-> FIN(断开连接))->s

十:服务器端

10.1:listen
int listen(int sockfd, int backlog);

功能:在参数1所在的套接字id上监听等待链接。
参数:sockfd 套接字id
backlog 允许链接的个数。
返回值:成功 0, 失败 -1;

10.2:accept
int accept(int sockfd, struct sockaddr *addr,socklen_t *addrlen);// 这里有阻塞

功能:从已经监听到的队列中取出有效的客户端链接并接入到当前程序。
参数:sockfd 套接字id
addr 如果该值为NULL ,表示不论客户端是谁都接入。
如果要获取客户端信息,则事先定义变量并传入变量地址,函数执行完毕将会将客户端信息存储到该变量中。
addrlen: 参数2的长度,如果参数2为NULL,则该值也为NULL;
如果参数不是NULL,&len;
一定要写成len = sizeof(struct sockaddr);

返回值:成功 返回一个用于通信的新套接字id;从该代码之后所有通信都基于该id, 失败 -1;

10.3:recv
ssize_t recv(int sockfd, void *buf, size_t len,int flags);

功能:从指定的sockfd套接字中以flags方式获取长度
为len字节的数据到指定的buff内存中。
参数:sockfd
如果服务器则是accept的返回值的新fd
如果客户端则是socket的返回值旧fd
buff 用来存储数据的本地内存,一般是数组或者
动态内存。
len 要获取的数据长度
flags 获取数据的方式,0 表示阻塞接受。

返回值:成功 表示接受的数据长度,一般小于等于len
失败 -1;

十一:客户端

11.1:connect
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

功能:该函数固定有客户端使用,表示从当前主机向目标
主机发起链接请求。
参数:sockfd 本地socket创建的套接子id
addr 远程目标主机的地址信息。
addrlen: 参数2的长度。
返回值:成功 0, 失败 -1;
ps:套接字不是单独给网络用的,可以用别名强转

11.2:send
int send(int sockfd, const void *msg, size_t len, int flags);

功能:从msg所在的内存中获取长度为len的数据以flags 方式写入到sockfd对应的套接字中。

参数:sockfd:如果是服务器则是accept的返回值新fd
如果是客户端则是sockfd的返回值旧fd

msg: 要发送的消息
len: 要发送的消息长度
flags :消息的发送方式。

返回值:成功 发送的字符长度, 失败 -1;

十二:实例

//ser
#include <netinet/in.h>
#include <netinet/ip.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h> /* See NOTES */
#include <time.h>
#include <unistd.h>
typedef struct sockaddr*(SA);
int main(int argc, char** argv)
{//监听套接字 功能检测是否有客户端 连连接服务器int listfd = socket(AF_INET, SOCK_STREAM, 0);if (-1 == listfd){perror("socket");return 1;}struct sockaddr_in ser, cli;bzero(&ser, sizeof(ser));bzero(&cli, sizeof(cli));ser.sin_family = AF_INET;ser.sin_port = htons(50000);// 代表本机地址  外部客户端可以连接到服务器ser.sin_addr.s_addr = INADDR_ANY;//任何人都可以连接,相当于ser.sin_addr.s_addr = 0int ret = bind(listfd, (SA)&ser, sizeof(ser));if (-1 == ret){perror("bind");return 1;}// 同一时刻可以服务器建立连接的排队数listen(listfd, 3);socklen_t len = sizeof(cli);//和客户端建立连接,并获得通信套接字,这个套接字就代表客户端int conn = accept(listfd, (SA)&cli, &len);if (-1 == conn){perror("accept");return 1;}while (1){char buf[512] = {0};int rec_ret= recv(conn, buf, sizeof(buf), 0);if(rec_ret<=0){break;}printf("from cli:%s\n",buf);time_t tm;time(&tm);sprintf(buf, "%s %s", buf, ctime(&tm));int sd_ret = send(conn, buf, strlen(buf), 0);if(sd_ret<=0){break;}}close(listfd);close(conn);// system("pause");return 0;
}
//cli
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h> /* See NOTES */
#include <time.h>
#include <unistd.h>
typedef struct sockaddr *(SA);int main(int argc, char **argv)
{int conn = socket(AF_INET, SOCK_STREAM, 0);if (-1 == conn){perror("socket");return 1;}struct sockaddr_in ser;bzero(&ser, sizeof(ser));ser.sin_family = AF_INET;ser.sin_port = htons(50000);// 代表本机地址  外部客户端可以连接到服务器ser.sin_addr.s_addr = inet_addr("192.168.116.130");int ret = connect(conn, (SA)&ser, sizeof(ser));if (-1 == ret){perror("connect");return 1;}while (1){char buf[512] = "hello,this tcp test";int sd_ret = send(conn, buf, strlen(buf), 0);if(sd_ret<=0){break;}bzero(buf, sizeof(buf));int ret_rec = recv(conn, buf, sizeof(buf), 0);if(ret_rec<=0){break;}printf("from  ser:%s\n",buf);sleep(1);}close(conn);// system("pause");return 0;
}

十三:tcp_cp_struct

//ser
#include <fcntl.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h> /* See NOTES */
#include <time.h>
#include <unistd.h>
typedef struct sockaddr*(SA);
typedef struct
{char name[256];int size;char buf[4096];int buf_size;} MSG;
int main(int argc, char** argv)
{//监听套接字 功能检测是否有客户端 连连接服务器int listfd = socket(AF_INET, SOCK_STREAM, 0);if (-1 == listfd){perror("socket");return 1;}struct sockaddr_in ser, cli;bzero(&ser, sizeof(ser));bzero(&cli, sizeof(cli));ser.sin_family = AF_INET;ser.sin_port = htons(50000);// 代表本机地址  外部客户端可以连接到服务器ser.sin_addr.s_addr = INADDR_ANY;int ret = bind(listfd, (SA)&ser, sizeof(ser));if (-1 == ret){perror("bind");return 1;}// 同一时刻可以服务器建立连接的排队数listen(listfd, 3);socklen_t len = sizeof(cli);//和客户端建立连接,并获得通信套接字,这个套接字就代表客户端int conn = accept(listfd, (SA)&cli, &len);if (-1 == conn){perror("accept");return 1;}MSG msg;bzero(&msg, sizeof(msg));int flag = 0;int fd = -1;int total_size = 0;int currnet_size = 0;while (1){int re_ret = recv(conn, &msg, sizeof(msg), 0);if (re_ret <= 0){break;}if (0 == flag){flag = 1;fd = open(msg.name, O_WRONLY | O_CREAT | O_TRUNC, 0666);if (-1 == fd){perror("open");return 1;}total_size = msg.size;}if (msg.buf_size <= 0){break;}write(fd, msg.buf, msg.buf_size);currnet_size += msg.buf_size;printf("size:%d\n", currnet_size);if (currnet_size == total_size){  //文件传输结束break;}bzero(&msg, sizeof(msg));strcpy(msg.buf, "go on");send(conn, &msg, sizeof(msg), 0);}close(listfd);close(conn);close(fd);// system("pause");return 0;
}
//cli
#include <arpa/inet.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h> /* See NOTES */
#include <time.h>
#include <unistd.h>
typedef struct sockaddr *(SA);
typedef struct
{char name[256];int size;char buf[4096];int buf_size;} MSG;
int main(int argc, char **argv)
{int conn = socket(AF_INET, SOCK_STREAM, 0);if (-1 == conn){perror("socket");return 1;}struct sockaddr_in ser;bzero(&ser, sizeof(ser));ser.sin_family = AF_INET;ser.sin_port = htons(50000);// 代表本机地址  外部客户端可以连接到服务器ser.sin_addr.s_addr = inet_addr("192.168.116.130");int ret = connect(conn, (SA)&ser, sizeof(ser));if (-1 == ret){perror("connect");return 1;}MSG msg;strcpy(msg.name, "2.png");struct stat st;ret = stat("/home/linux/1.png", &st);if (-1 == ret){perror("stat");return 1;}msg.size = st.st_size;int fd = open("/home/linux/1.png", O_RDONLY);if (-1 == fd){perror("open");return 1;}while (1){msg.buf_size = read(fd, msg.buf, sizeof(msg.buf));send(conn, &msg, sizeof(msg), 0);  // 固定大小的方式if (msg.buf_size <= 0){break;}bzero(&msg, sizeof(msg));recv(conn, &msg, sizeof(msg), 0);}close(conn);// system("pause");return 0;
}
http://www.lryc.cn/news/596547.html

相关文章:

  • 质量即服务:从测试策略到平台运营的全链路作战手册
  • 重生学AI第十九集:VGG16的使用以及模型的保存与加载
  • 【期末考试复习】计算机组成原理 - 直接补码阵列乘法器
  • 【接口自动化】pytest的基本使用
  • CSS+JavaScript 禁用浏览器复制功能的几种方法
  • web登录页面
  • 黑马点评练习题-给店铺类型查询业务添加缓存(String和List实现)
  • kafka4.0集群部署
  • 数据结构01:链表
  • docker compose 安装使用笔记
  • Docker实战:使用Docker部署TeamMapper思维导图工具
  • 【实时Linux实战系列】基于实时Linux的传感器网络设计
  • Spring Boot音乐服务器项目-登录模块
  • 【论文阅读】Fast-BEV: A Fast and Strong Bird’s-Eye View Perception Baseline
  • 基于VU13P的百G光纤FMC高性能处理板
  • Rust实战:决策树与随机森林实现
  • 板凳-------Mysql cookbook学习 (十二--------5)
  • 【RAG优化】PDF复杂表格解析问题分析
  • 阶段1--Linux中的文件服务器(FTP、NAS、SSH)
  • 从差异到协同:OKR 与 KPI 的管理逻辑,Moka 让适配更简单
  • 苹果app应用ipa文件程序开发后如何运行到苹果iOS真机上测试?
  • C# 析构函数
  • 【论文阅读 | TIV 2024 | CDC-YOLOFusion:利用跨尺度动态卷积融合实现可见光-红外目标检测】
  • 2025年07月22日Github流行趋势
  • 坑机介绍学习研究
  • 激活函数Focal Loss 详解​
  • 数组——初识数据结构
  • DMZ网络安全基础知识
  • [3-02-02].第04节:开发应用 - RequestMapping注解的属性2
  • Fluent许可与网络安全策略