所谓双向数据传输指的是客户端与服务端之间可以无差异的实现数据交互,此类功能实现的核心原理是通过创建CreateThread()函数多线程分别接收和发送数据包,这样一旦套接字被建立则两者都可以异步发送消息,本章将实现简单的双向交互功能。

首先我们需要封装两个函数,这里RecvFunction函数用于接收数据,SendFunction函数则用于发送数据,这两段代码在服务端与客户端之间是一致的两者可被共用。

#include <iostream>
#include <Winsock2.h> 
#include <windows.h>
#pragma comment (lib, "ws2_32")
#define BUF_SIZE 6400 // 接收数据线程
DWORD WINAPI RecvFunction(LPVOID lpParam)
{
SOCKET sClient = *(SOCKET*)lpParam;
int retVal;
char bufRecv[BUF_SIZE];
memset(bufRecv, 0, sizeof(bufRecv));
while (1)
{
retVal = recv(sClient, bufRecv, BUF_SIZE, 0);
if (retVal == SOCKET_ERROR)
{
printf("返回错误 \n");
break;
}
else
{
printf("收到服务器消息: %s \n", bufRecv);
}
}
return 0;
} // 发送数据线程
DWORD WINAPI SendFunction(LPVOID lpParam)
{
SOCKET sClient = *(SOCKET*)lpParam;
int retVal;
char bufSend[BUF_SIZE];
memset(bufSend, 0, sizeof(bufSend));
while (1)
{
gets_s(bufSend);
retVal = send(sClient, bufSend, strlen(bufSend) + sizeof(char), 0);
if (retVal == SOCKET_ERROR)
{
printf("发送错误 \n");
break;
}
}
return 0;
}

14.4.1 服务端实现

对于服务端代码而言,一旦accept函数接收到有客户端连接后则自动将该sClient指针传输到子线程内执行,这样即可实现两者功能互不干扰。程序中通过使用CreateThread函数创建了两个线程来处理与客户端之间的发送和接收数据。将SendFunctionRecvFunction作为参数传递给线程,并与新的客户端套接字一起传递。线程存储在变量hThread1hThread2中。

int main(int argc, char* argv[])
{
// 初始化套接字动态库
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
return 1;
} // 创建服务段套接字
SOCKET sServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sServer == INVALID_SOCKET)
{
WSACleanup();
return -1;
} // 服务端地址
sockaddr_in addrServ;
addrServ.sin_family = AF_INET;
addrServ.sin_port = htons(9999);
addrServ.sin_addr.s_addr = htonl(INADDR_ANY); // 绑定套接字
if (bind(sServer, (const struct sockaddr*)&addrServ, sizeof(addrServ)) == SOCKET_ERROR)
{
closesocket(sServer);
WSACleanup();
return -1;
} // 监听套接字
if (listen(sServer, 5) == SOCKET_ERROR)
{
closesocket(sServer);
WSACleanup();
return -1;
} SOCKET sClient;
sockaddr_in addrClient;
int addrClientLen = sizeof(addrClient); // 接收数据
sClient = accept(sServer, (sockaddr FAR*) & addrClient, &addrClientLen);
if (sClient == INVALID_SOCKET)
{
closesocket(sServer);
WSACleanup();
return -1;
} printf("接收客户端 IP:[%s] --> port:[%d] \n", inet_ntoa(addrClient.sin_addr), ntohs(addrClient.sin_port)); // 分配线程
HANDLE hThread1, hThread2; hThread1 = CreateThread(NULL, NULL, SendFunction, (LPVOID*)&sClient, 0, 0);
hThread2 = CreateThread(NULL, NULL, RecvFunction, (LPVOID*)&sClient, 0, 0); WaitForSingleObject(hThread1, INFINITE);
WaitForSingleObject(hThread2, INFINITE);
CloseHandle(hThread1);
CloseHandle(hThread2); closesocket(sClient);
WSACleanup();
return 0;
}

14.4.2 客户端实现

客户端的实现与服务端保持一致,唯一的区别在于客户端通过connect()主动向服务端发送连接请求,只要有新的连接被建立则将通过CreateThread函数创建线程,SendFunctionRecvFunction函数分别用于发送与接收功能。

int main(int argc, char* argv[])
{
WSADATA wsaData; // 初始化库
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
return 1;
} // 服务器套接字
SOCKET sHost = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sHost == INVALID_SOCKET)
{
WSACleanup();
return -1;
} SOCKADDR_IN servAddr;
servAddr.sin_family = AF_INET;
servAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
servAddr.sin_port = htons(9999); // 连接服务器
if (connect(sHost, (LPSOCKADDR)&servAddr, sizeof(servAddr)) == SOCKET_ERROR)
{
closesocket(sHost);
WSACleanup();
return -1;
} printf("连接到服务器 IP:[%s] --> port:[%d] \n", inet_ntoa(servAddr.sin_addr), ntohs(servAddr.sin_port)); // 分别创建两个线程
HANDLE hThread1, hThread2; hThread1 = CreateThread(NULL, NULL, SendFunction, (LPVOID)&sHost, 0, 0);
hThread2 = CreateThread(NULL, NULL, RecvFunction, (LPVOID)&sHost, 0, 0); WaitForSingleObject(hThread1, INFINITE);
WaitForSingleObject(hThread2, INFINITE); CloseHandle(hThread1);
CloseHandle(hThread2); closesocket(sHost);
WSACleanup();
return 0;
}

编译并运行这两个程序,读者可自行测试,不论是在服务端还是客户端均可以实现双向数据通信功能,输出效果如下图所示;

14.4 Socket 双向数据通信的更多相关文章

  1. java中关于SSL/TSL的介绍和如何实现SSL Socket双向认证

    一.        SSL概述 SSL协议采用数字证书及数字签名进行双端实体认证,用非对称加密算法进行密钥协商,用对称加密算法将数据加密后进行传输以保证数据的保密性,并且通过计算数字摘要来验证数据在传 ...

  2. 《精通android网络开发》--使用Socket实现数据通信

    No1: 网络传输应用通常使用TCP.IP或UDP这三种协议实现数据传输.在传输数据的过程中,需要通过一个双向的通信连接实现数据的交互.在这个传输过程中,通常将这个双向链路的一端称为Socket,一个 ...

  3. unity3D中使用Socket进行数据通信(二)

    上一篇博客主要介绍了使用socket搭建服务端和client程序,这一篇来说说socket的数据传输,我们使用socket的目的是解决点对点之间的数据传输,之前提到了socket中一个重要的概念:po ...

  4. unity3D中使用Socket进行数据通信(一)

    公司今年3D产品的工作中心主要集中在提高产品深度上,通过对竞争产品的分析,发现我们的缺陷在于多人在线与后台管理部分,多人在线使用unity自带的Network能够搞定,后台部分前段时间主要研究了下Sq ...

  5. (转)python标准库中socket模块详解

    python标准库中socket模块详解 socket模块简介 原文:http://www.lybbn.cn/data/datas.php?yw=71 网络上的两个程序通过一个双向的通信连接实现数据的 ...

  6. Socket类的用法

    原文:http://www.cnblogs.com/Elijah/archive/2011/11/29/2268047.html Socket可以理解成一个IP地址加一个端口,构成的一个“插座”... ...

  7. 轮询以及webSocket与socket.io原理

    概述: 首先,我们知道,起初的http协议只是为了能够进行通信而被创造出来(也就是请求-响应的过程).并没有双向通信这一说,后面随着历史业务的需求,人们使用轮询http来解决双向通信也就是使用xhr或 ...

  8. 在web浏览器上显示室内温度(nodeJs+arduino+socket.io)

    上次的nodejs操作arduino入门篇中实现了如何连接arduino.这次我们来实现通过arduino测量室内温度并在浏览器上显示出来. [所需材料] 硬件:LM35温度传感器,arduino u ...

  9. python异常处理、反射、socket

    一.isinstance 判断对象是否为类的实例 n1 = print isinstance(n1,int) class A: pass class B(A): pass b= B() print i ...

  10. 使用socket.io开发简单群聊功能

    1.新建package.json文件: { "name": "socket-chat-example", "version": " ...

随机推荐

  1. 解密Prompt系列23.大模型幻觉分类&归因&检测&缓解方案脑图全梳理

    上一章我们主要聊聊RAG场景下的幻觉检测和解决方案,这一章我们单独针对大模型的幻觉问题,从幻觉类型,幻觉来源,幻觉检测,幻觉缓解这四个方向进行整理.这里就不细说任意一种方法了,因为说不完根本说不完,索 ...

  2. termius macos 破解版,激活版下载,永久激活,亲测可用

    termius 是一款非常值得推荐的 SSH/SFTP 跨平台终端工具,其十分亮眼的功能是可以上传文件夹,这是其他几款终端工具都不具备的,比如说 macOS 自带的终端.号称 21 世纪最强终端的 w ...

  3. Problem A - Sequence with Digits (数学推导)

    题意: 已知 \(a_1\) 求 \(a_k\) ,推导公式见题面. #include<bits/stdc++.h> using namespace std; typedef long l ...

  4. Goolge Kick Start Round A 2020 (A ~ D题题解)

    比赛链接:kick start Round A 2020 A. Allocation 题目链接 题意 给出 \(N\) 栋房子的价格,第 \(i\) 栋房子的价格为 \(A_i\),你有 \(B\) ...

  5. RPC与Http的区别

    一.远程调用方式 无论是微服务还是分布式服务(都是SOA,都是面向服务编程),都面临着服务间的远程调用.那么服务间的远程调用方式有哪些呢? 常见的远程调用方式有以下几种: RPC:Remote Pro ...

  6. Java 内存管理最佳实践

    本文翻译自国外论坛 medium,原文地址:https://medium.com/@fullstacktips/best-practices-for-memory-management-in-java ...

  7. freeswitch号码变化方案

    概述 freeswitch是一款简单易用的开源音视频软交换平台. 在生产环境中,由于各个线路的号码规则并不统一,经常需要针对中继线路做号码变换的方案. 本文主要介绍fs中有哪些可选的号码变换方案. 环 ...

  8. socket TCP DPT 网络编程

    复习: ARP协议: 广播和单播 通过ip地址获得mac地址 机器A发起一个arp请求(只包含A的ip地址) 交换机接收到请求,广播这条消息 所有的机器都会接受到这条请求,只有需要寻找的机器B的ip地 ...

  9. 【SI】source insight4 添加指定类型的文件

    Options->File Type Options 红框可选择是否将指定类型的文件添加到工程 绿框可添加自定义文件类型,如汇编*.s;*.S 蓝框可新增文件类别,用于自定义文件类型 如不需将t ...

  10. [转帖]Java程序在K8S容器部署CPU和Memory资源限制相关设置

    2019-04-297279 版权 本文涉及的产品 容器服务 Serverless 版 ACK Serverless,317元额度 多规格 推荐场景: 立即试用 容器镜像服务 ACR,镜像仓库100个 ...