14.7 Socket 循环结构体传输
在上述内容中笔者通过一个简单的案例给大家介绍了在套接字编程中如何传递结构体数据,本章将继续延申结构体传输,在某些时候例如我们需要传输一些当前系统的进程列表信息,或者是当前主机中的目录文件,此时就需要使用循环结构体传输功能,循环传输结构体的关键点在于,客户端发送结构体数据之前需要通过一次通信来告诉服务端需要接收的次数,当服务端接收到次数时则可利用接收计数器依次循环接收数据直到客户端完整所有数据包的发送。
14.7.1 服务端实现
多条结构体的传输方式与单条从原理上一致,只是多条结构体在传输时需要提前告知服务端我需要分几次将结构体传输给对方,因为数据包最大单次可发送8192字节,所以如果结构过多则需要分批次进行传输,如下是服务端实现代码片段,在代码中首先我们接收客户端发来的循环次数,该次数是一个字符串类型的,为了能用于循环体内,需要通过atoi(count)将其转换为一个整数,接着就是在循环体内不断地调用recv函数接收数据包,直到循环结束为止。
#include <iostream>
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")
typedef struct
{
char HostName[32];
char Buffer[32];
}message;
int main(int argc, char* argv[])
{
WSADATA WSAData;
SOCKET sock;
WSAStartup(MAKEWORD(2, 0), &WSAData);
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == INVALID_SOCKET)
{
std::cout << "创建套接字失败" << std::endl;
}
struct sockaddr_in ServerAddr;
ServerAddr.sin_family = AF_INET;
ServerAddr.sin_port = htons(9999);
ServerAddr.sin_addr.s_addr = INADDR_ANY;
auto res = bind(sock, (LPSOCKADDR)&ServerAddr, sizeof(ServerAddr));
if (res == SOCKET_ERROR)
{
std::cout << "绑定失败" << std::endl;
}
res = listen(sock, 10);
if (res == SOCKET_ERROR)
{
std::cout << "侦听失败" << std::endl;
}
SOCKET msgsock;
msgsock = accept(sock, (LPSOCKADDR)0, (int*)0);
if (msgsock != INVALID_SOCKET)
{
// 接收循环次数
char count[32] = { 0 };
int recv_count_flag = recv(msgsock, count, sizeof(count), 0);
if (recv_count_flag != 0)
{
// 得到需要循环接收的次数
int index = atoi(count);
std::cout << "总共循环接收: " << count << " 次" << std::endl;
for (int x = 0; x < index; x++)
{
char recv_buf[4096] = { 0 };
// 循环输出接收结果
int recv_flag = recv(msgsock, recv_buf, sizeof(recv_buf), 0);
if (recv_flag != 0)
{
// 接收到结构,强制类型转换
message* msg = (message*)recv_buf;
std::cout << "用户名: " << msg->HostName << "数据: " << msg->Buffer << std::endl;
// 发送成功标志
send(msgsock, "success", 7, 0);
}
}
}
}
closesocket(sock);
WSACleanup();
return 0;
}
14.7.2 客户端实现
相对于服务端而言,客户端首先需要准备好一个待发送结构体链表,此处通过使用vector<message>的方式接收结构体链表,并通过sprintf()函数将循环次数由整数格式化为字符串,并将次数发送给服务端,当服务端接收到发送次数后会等待客户端向其发送对应数量的结构体,此时客户端只需要send循环发送即可。
#include <iostream>
#include <vector>
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")
using namespace std;
typedef struct
{
char HostName[32];
char Buffer[32];
}message;
message msg;
int main(int argc, char* argv[])
{
WSADATA WSAData;
SOCKET sock;
WSAStartup(MAKEWORD(2, 0), &WSAData);
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == INVALID_SOCKET)
{
std::cout << "创建套接字失败" << std::endl;
}
struct sockaddr_in ClientAddr;
ClientAddr.sin_family = AF_INET;
ClientAddr.sin_port = htons(9999);
ClientAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
auto res = connect(sock, (LPSOCKADDR)&ClientAddr, sizeof(ClientAddr));
if (res == SOCKET_ERROR)
{
std::cout << "链接失败." << std::endl;
}
// 模拟元素填充
std::vector<message> vect;
for (int x = 0; x < 10; x++)
{
message ptr;
// 填充参数
sprintf(ptr.HostName, "lyshark %d", x);
sprintf(ptr.Buffer, "hello lyshark %d", x);
vect.push_back(ptr);
}
// 发送循环次数
char count[32] = { 0 };
// 整数转为字符串
sprintf(count, "%d", vect.size());
int send_count_flag = send(sock, count, sizeof(count), 0);
if (send_count_flag != 0)
{
std::cout << "发送循环次数: " << count << std::endl;
// 循环发送数据
for (int x = 0; x < vect.size(); x++)
{
char send_buf[4096] = { 0 };
// 发送字节序
memcpy(send_buf, &vect[x], sizeof(message));
int send_flag = send(sock, send_buf, sizeof(send_buf), 0);
if (send_flag != 0)
{
char recv_buf[32] = { 0 };
recv(sock, recv_buf, sizeof(recv_buf), 0);
std::cout << "发送完成,接收状态码: " << recv_buf << std::endl;
}
}
}
closesocket(sock);
WSACleanup();
return 0;
}
至此读者可分别编译并运行服务端与客户端,此时会看到如下图所示的结构体输出;

14.7 Socket 循环结构体传输的更多相关文章
- C#与C++通过socket传送结构体
C#服务端: using System; using System.Net.Sockets; using System.Net; using System.IO; using System.Diagn ...
- Bash脚本编程学习笔记07:循环结构体
本篇中涉及到算术运算,使用了$[]这种我未在官方手册中见到的用法,但是确实可用的,在此前的博文<Bash脚本编程学习笔记03:算术运算>中我有说明不要使用,不过自己忘记了.大家还是尽量使用 ...
- socket发送结构体
struct send_info {char info_from[20]; //发送者IDchar info_to[20]; //接收者IDint info_length; //发送的消息主体的长度c ...
- 2. socket结构体——表示socket地址
一.两种通用socket结构体 1. sockaddr struct sockaddr { sa_family_t sa_family; // 地址族 char sa_data[14]; // 存放s ...
- C# Socket 入门4 UPD 发送结构体(转)
今天我们来学 socket 发送结构体 1. 先看要发送的结构体 using System; using System.Collections.Generic; using System.Text; ...
- 全国计算机等级考试二级教程-C语言程序设计_第14章_结构体、共用体和用户定义类型
函数的返回值是结构体类型 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> struct ...
- IPv4地址结构体sockaddr_in详解
sockaddr_in结构体定义 struct sockaddr_in { sa_family_t sin_family; //地址族(Address Family) uint16_t sin_por ...
- C++ 结构体+数组+取随机数 案例(打印3名老师 带着 5名学生)结构体
1 //结构体案列 2 3 #include<iostream> 4 #include<string> 5 #include<ctime> 6 using name ...
- C与C# socket 跨平台通讯传输结构体
最近需要写一个C组成的服务器端与C#的客户端进行交互的软件,刚开始写的时候发现C#端解析时候出现了故障,经过仔细研究后发现原因是发送方传输太快,出现了所谓粘包的现象.也就是在C#端的Receive() ...
- struct socket结构体详解
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://weiguozhihui.blog.51cto.com/3060615/15852 ...
随机推荐
- 【短道速滑六】古老的视频去噪算法(FLT_GradualNoise)解析并优化,可实现1920*1080 YUV数据400fps的处理能力。
这个好像没有啥对应的论文可以找到,在百度上搜索也能找到一些相关的资料,不过就直接是代码,可以看到其实来自于一个叫做DScaler的项目,在github上目前还能找到该项目的完整资料. 详见:https ...
- Codeforces Round #721 (Div. 2) AB思维,B2博弈,C题map
补题链接:Here 1527A. And Then There Were K 题目大意: 给一个正整数n,求最大的k,使得 \(n \& (n−1) \& (n−2) \& ( ...
- L1-046 整除光棍 (20分)
问题描述 这里所谓的"光棍",并不是指单身汪啦~ 说的是全部由1组成的数字,比如1.11.111.1111等.传说任何一个光棍都能被一个不以5结尾的奇数整除.比如,111111就可 ...
- 密集计算场景下的 JNI 实战
作者:vivo 互联网服务器团队- Wei Qianzi.Li Haoxuan 在 Java 发展历程中,JNI 一直都是一个不可或缺的角色,但是在实际的项目开发中,JNI 这项技术应用的很少.在笔者 ...
- ngix反向代理服务器
Nginx ("engine x") 是一个高性能的HTTP 和反向代理 服务器,在大负载的情况下表现十分优秀. 1.正向代理 正向代理也是大家最常接触的到的代理模式.正向代理最大 ...
- 函数计算 HTTP 触发器支持异步,解放双手搭建 Web 服务
作者| 阿里云Serverless技术专家 澈尔 当前阿里云函数计算支持两种类型的函数:事件函数和 HTTP 函数.其中 HTTP 函数结合 HTTP 触发器,能够支持用户直接通过 HTTP 请求利用 ...
- java读取解析endnote文件
有些项目中会要求代码解析endnote文献资料获取一些标准的信息,例如XX在某著名期刊上发表了某篇文章,关于发表文章的这个事情的描述就会给坐着一个endnote文件来记录文章名称.作者.期刊名称.出版 ...
- 【面试题精讲】为什么G1收集器不需要调优性能也很优秀
G1(Garbage-First)收集器是一种面向服务器端应用的垃圾回收器,它在JDK 7u4版本中首次引入,主要用于替代CMS(Concurrent Mark Sweep)收集器.相比于其他垃圾回收 ...
- Kafka的部分初始化参数的学习与整理
Kafka的部分初始化参数的学习与整理 背景 前段时间跟同事一起处理过kafka的topic offset的retention 时间与 log 的retention时间不一致. 导致消息还有, 但是o ...
- [转帖]Linux之/etc/fstab文件讲解
https://www.cnblogs.com/FengGeBlog/p/10178824.html /etc/fstab是用来存放文件系统的静态信息的文件.位于/etc/目录下,可以用命令less ...