前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >14.7 Socket 循环结构体传输

14.7 Socket 循环结构体传输

原创
作者头像
王瑞MVP
发布于 2023-10-16 06:56:37
发布于 2023-10-16 06:56:37
23700
代码可运行
举报
运行总次数:0
代码可运行

在上述内容中笔者通过一个简单的案例给大家介绍了在套接字编程中如何传递结构体数据,本章将继续延申结构体传输,在某些时候例如我们需要传输一些当前系统的进程列表信息,或者是当前主机中的目录文件,此时就需要使用循环结构体传输功能,循环传输结构体的关键点在于,客户端发送结构体数据之前需要通过一次通信来告诉服务端需要接收的次数,当服务端接收到次数时则可利用接收计数器依次循环接收数据直到客户端完整所有数据包的发送。

14.7.1 服务端实现

多条结构体的传输方式与单条从原理上一致,只是多条结构体在传输时需要提前告知服务端我需要分几次将结构体传输给对方,因为数据包最大单次可发送8192字节,所以如果结构过多则需要分批次进行传输,如下是服务端实现代码片段,在代码中首先我们接收客户端发来的循环次数,该次数是一个字符串类型的,为了能用于循环体内,需要通过atoi(count)将其转换为一个整数,接着就是在循环体内不断地调用recv函数接收数据包,直到循环结束为止。

代码语言:c
代码运行次数:0
运行
AI代码解释
复制
#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循环发送即可。

代码语言:c
代码运行次数:0
运行
AI代码解释
复制
#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;
}

至此读者可分别编译并运行服务端与客户端,此时会看到如下图所示的结构体输出;

本文作者: 王瑞

本文链接: https://www.lyshark.com/post/acaf6a13.html

版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
14.6 Socket 应用结构体传输
当在套接字编程中传输结构体时,可以将结构体序列化为字符串(即把结构体的所有成员打包成一个字符串),然后将字符串通过套接字传输到对端,接收方可以将字符串解析为结构体,然后使用其中的成员数据。这种方法通常被称为序列化(Serialization)和反序列化(Deserialization),本章中我们可以采用将一个结构体序列化为一个纯字符串,然后将该字符串通过套接字传输给对端,当对端收到后只需要将字节序强制转换为对等的结构体指针即可实现对该结构的解析。
王瑞MVP
2023/10/16
3700
14.6 Socket 应用结构体传输
14.3 Socket 字符串分块传输
首先为什么要实行分块传输字符串,一般而言Socket套接字最长发送的字节数为8192字节,如果发送的字节超出了此范围则后续部分会被自动截断,此时将字符串进行分块传输将显得格外重要,分块传输的关键在于封装实现一个字符串切割函数,将特定缓冲区内的字串动态切割成一个个小的子块,当切割结束后会得到该数据块的个数,此时通过套接字将个数发送至服务端此时服务端在依次循环接收数据包直到接收完所有数据包之后在组合并显示即可。
王瑞MVP
2023/10/13
4200
14.3 Socket 字符串分块传输
14.11 Socket 基于时间加密通信
在之前的代码中我们并没有对套接字进行加密,在未加密状态下我们所有的通信内容都是明文传输的,这种方式在学习时可以使用但在真正的开发环境中必须要对数据包进行加密,此处笔者将演示一种基于时间的加密方法,该加密方法的优势是数据包每次发送均不一致,但数据包内的内容是一致的,当抓包后会发现每次传输的数据包密文是随机变化的,但内容始终保持一致,也就是说两个拥有相同内容的数据被加密后,数据包密文不同,其主要运用了基于当前时间戳的通信机制。
王瑞MVP
2023/10/18
3900
14.11 Socket 基于时间加密通信
14.8 Socket 一收一发通信
通常情况下我们在编写套接字通信程序时都会实现一收一发的通信模式,当客户端发送数据到服务端后,我们希望服务端处理请求后同样返回给我们一个状态值,并以此判断我们的请求是否被执行成功了,另外增加收发同步有助于避免数据包粘包问题的产生,在多数开发场景中我们都会实现该功能。
王瑞MVP
2023/10/16
2930
14.8 Socket 一收一发通信
14.1 Socket 套接字编程入门
Winsock是Windows操作系统上的套接字API,用于在网络上进行数据通信。套接字通信是一种允许应用程序在计算机网络上进行实时数据交换的技术。通过使用Windows提供的API,应用程序可以创建一个套接字来进行数据通信。这个套接字可以绑定到一个端口,以允许其他应用程序连接它。另外,Winsock可以使用TCP/IP、UDP等协议来完成不同类型的数据传输任务。在网络应用程序开发中,套接字通信可以帮助应用程序开发者实现客户端/服务端模型,并实现数据的可靠传输。
王瑞MVP
2023/10/11
4730
14.1 Socket 套接字编程入门
14.10 Socket 套接字选择通信
对于网络通信中的服务端来说,显然不可能是一对一的,我们所希望的是服务端启用一份则可以选择性的与特定一个客户端通信,而当不需要与客户端通信时,则只需要将该套接字挂到链表中存储并等待后续操作,套接字服务端通过多线程实现存储套接字和选择通信,可以提高服务端的并发性能,使其能够同时处理多个客户端的请求。在实际应用场景中,这种技术被广泛应用于网络编程、互联网应用等领域。
王瑞MVP
2023/10/18
2670
14.10 Socket 套接字选择通信
20.5 OpenSSL 套接字RSA加密传输
RSA算法同样可以用于加密传输,但此类加密算法虽然非常安全,但通常不会用于大量的数据传输,这是因为RSA算法加解密过程涉及大量的数学运算,尤其是模幂运算(即计算大数的幂模运算),这些运算对于计算机而言是十分耗时。
王瑞MVP
2023/11/04
4110
20.5 OpenSSL 套接字RSA加密传输
C/C++ 使用Socket模拟远程CMD
服务端(server) #include <stdio.h> #include <winsock2.h> #pragma comment(lib,"ws2_32.lib") //把ws2_32.lib加到Link页的连接库 #define PORT 15001 //通信的端口(指服务器端) #define ERROR 0 #define BUFFER_SIZE 1024 //注意:此Server端数据接收缓冲区 >= Clie
王瑞MVP
2022/12/28
5870
c++ 网络编程(四)TCP/IP LINUX/windows下 socket 基于I/O复用的服务器端代码 解决多进程服务端创建进程资源浪费问题
原文链接:https://www.cnblogs.com/DOMLX/p/9613861.html
徐飞机
2018/09/30
1.7K0
c++ 网络编程(四)TCP/IP LINUX/windows下  socket 基于I/O复用的服务器端代码    解决多进程服务端创建进程资源浪费问题
20.6 OpenSSL 套接字分发RSA公钥
通过上一节的学习读者应该能够更好的理解RSA加密算法在套接字传输中的使用技巧,但上述代码其实并不算完美的,因为我们的公钥和私钥都必须存储在本地文本中且公钥与私钥是固定的无法做到更好的保护效果,而一旦公钥与私钥泄密则整个传输流程都将会变得不安全,最好的保护效果是RSA密钥在每次通信时都进行变换,依次来实现随机密钥对的功能。
王瑞MVP
2023/11/04
2200
20.6 OpenSSL 套接字分发RSA公钥
C/C++ 实现Socket交互式服务端
在 Windows 操作系统中,原生提供了强大的网络编程支持,允许开发者使用 Socket API 进行网络通信,通过 Socket API,开发者可以创建、连接、发送和接收数据,实现网络通信。本文将深入探讨如何通过调用原生网络 API 实现同步远程通信,并介绍了一个交互式 Socket 类的封装,提升了编写交互式服务器的便利性。
王瑞MVP
2023/11/25
4920
C/C++ 实现Socket交互式服务端
C++ 使用Socket实现主机间的UDP/TCP通信
服务器端的代码做了跨平台(POSIX和WINDOWS),基于POSIX平台(Linux、Mac OS X、PlayStation等)使用sys/socket.h库,windows平台使用winsock2.h库。 客户端代码因为基本都在windows运行,所以没做跨平台,需要的话你可以参考服务器端代码自己做一下。 文中写的函数原型均为windows平台,部分函数的返回类型或参数类型在POSIX会有不同。
六月丶
2023/01/01
3.1K0
C++ 使用Socket实现主机间的UDP/TCP通信
使用socket实现TCP和UDP传输
转载自:https://blog.csdn.net/timmiy/article/details/51946093
战神伽罗
2019/09/03
1.7K0
使用socket实现TCP和UDP传输
【socket笔记】TCP、UDP通信总结
Socket的英文原义是“孔”或“插座”。在编程中,Socket被称做套接字,是网络通信中的一种约定。Socket编程的应用无处不在,我们平时用的QQ、微信、浏览器等程序,都与Socket编程有关。我们平时使用浏览器查资料,这个过程的技术原理是怎样的呢?
正念君
2019/11/28
4.1K0
【socket笔记】TCP、UDP通信总结
20.4 OpenSSL 套接字AES加密传输
在读者了解了加密算法的具体使用流程后,那么我们就可以使用这些加密算法对网络中的数据包进行加密处理,加密算法此处我们先采用AES算法,在网络通信中,只需要在发送数据之前对特定字符串进行加密处理,而在接收到数据后在使用相同的算法对数据进行恢复即可,读者如果有了套接字编程的基础,那么理解这段代码将变得很容易。
王瑞MVP
2023/11/02
3070
20.4 OpenSSL 套接字AES加密传输
驱动开发:内核封装TDI网络通信接口
在上一篇文章《驱动开发:内核封装WSK网络通信接口》中,LyShark已经带大家看过了如何通过WSK接口实现套接字通信,但WSK实现的通信是内核与内核模块之间的,而如果需要内核与应用层之间通信则使用TDK会更好一些因为它更接近应用层,本章将使用TDK实现,TDI全称传输驱动接口,其主要负责连接Socket和协议驱动,用于实现访问传输层的功能,该接口比NDIS更接近于应用层,在早期Win系统中常用于实现过滤防火墙,同样经过封装后也可实现通信功能,本章将运用TDI接口实现驱动与应用层之间传输字符串,结构体,多线程收发等技术。
王瑞MVP
2022/11/04
6680
驱动开发:内核封装TDI网络通信接口
socket基本连接
基本操作 服务端 #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #include <iostream> #include <string.h> int main(int argc, char* argv[]) { std::cout << "begin" << std::endl; //1.创建一个侦听socket int listenfd
opencode
2022/12/26
6720
UDP协议 sendto 和 recvfrom 浅析与示例
  UDP(user datagram protocol)用户数据报协议,属于传输层。
全栈程序员站长
2022/09/06
1.3K0
UDP协议 sendto 和 recvfrom 浅析与示例
TCP Socket性能优化秘籍:掌握read、recv、readv、write、send、sendv的最佳实践
TCP Socket在网络通信中的重要性体现在其提供了可靠的数据传输、连接性、多路复用等特性,是实现各种网络应用的基础,同时具有广泛的兼容性。它的存在使得网络通信更加可靠、高效和方便。其重要性如下:
Lion 莱恩呀
2024/08/02
1.3K0
TCP Socket性能优化秘籍:掌握read、recv、readv、write、send、sendv的最佳实践
UDP-Socket一般流程(Windows)
一、 服务端构建步骤 1.初始化套接字环境WSAStartup 2.初始化地址和端口 3.创建UDP套接字socket 4.绑定端口bind 5.用recvfrom接收数据 6.用sendto发送数据 7.退出或者返回5步骤继续 二、客户端构建步骤 1.初始化套接字环境WSAStartup 2.初始化地址和端口 3.创建UDP套接字socket 4.用sendto发送数据 5.用recvfrom接收数据 三、示例代码 Sever: #include <winso
TSINGEYE清眸物联
2023/01/04
5040
相关推荐
14.6 Socket 应用结构体传输
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验