当前位置: 首页 > 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.dtcms.com/a/293274.html

相关文章:

  • 帆软实现审批流配置
  • C++ 模板库map数据结构的概念和使用案例
  • Rabbit安装
  • vben ruoyi 数据字典解决方案
  • 16.多生成树MSTP
  • Linux文件系统理解1
  • Selenium+Java 自动化测试入门到实践:从环境搭建到元素操作
  • ubuntu22.04 录视屏软件推荐
  • Three.js 实现梦幻星河流光粒子特效原理与实践
  • Redis 5.0中的 Stream是什么?
  • C语言(20250722)
  • 21. `taskSlotTable`和`jobLeaderService`启动
  • 使用空间数据训练机器学习模型的实用工作流程
  • An error occurred at line: 1 in the generated java file问题处理及tomcat指定对应的jdk运行
  • Dify工作流:爬虫文章到AI知识库
  • 【OD机试】数组和最大
  • Java基础环境配置
  • 从零开始学习大模型之文本数据处理
  • BEV-LaneDet
  • 网络编程---网络基础知识
  • 【文本分析】使用LDA模型进行主题建模——李牧南等(2024)《科研管理》、马鸿佳等(2025)《南开管理评论》的复现
  • 24. 两两交换链表中的节点
  • 线程池excutor 和 submit区别 关于异常处理,请详细说明,会吞掉异常吗,需要捕获吗
  • vue3:十八、内容管理-实现行内图片的预览、审核功能
  • Python--numpy基础知识
  • 海洋大地测量基准与水下导航系列之九我国海洋PNT最新技术进展(中)
  • Qt开发环境搭建全攻略(Windows+Linux+macOS)
  • 14.8 LLaMA2-7B×Dolly-15K实战:从准确率63%到89%,如何用优质数据让大模型性能飙升42%?
  • 17-VRRP
  • 汉诺塔问题