所谓双向数据传输指的是客户端与服务端之间可以无差异的实现数据交互,此类功能实现的核心原理是通过创建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. sed 流编辑器

    一.简介 非交互式的处理 一行一行的读入处理 占用系统空间少 大文件一般用sed节省内存 语法:语法 sed [选项] '行的定位 动作' 文件... 参数 说明 -e 允许进行多项编辑 -n 静默输 ...

  2. Grafana--双Y轴

    grafana版本:6.5.2 背景:同一面板里想展示各实例与集群在一段时间范围内,平均每秒执行命令数,但是由于数值差异太大,曲线图抖动不明显,实例的更近乎于一条直线,所以设置双Y轴,可更直观的展示线 ...

  3. Python | __init__.py的神奇用法

    0._init_.py 在Python工程里,当python检测到一个目录下存在_init_.py文件时,python就会把它当成一个模块(module).Module跟C++的命名空间和Java的P ...

  4. vue 使用print.js实现前端打印功能

    https://blog.csdn.net/cccdf_jjj/article/details/99563682 插件vue-print-nb实现前端打印当前页面功能 https://blog.csd ...

  5. Vue 大屏可视化 铺满全屏

    https://blog.csdn.net/u011097323/article/details/106728221?utm_medium=distribute.pc_aggpage_search_r ...

  6. ShardingSphere 使用 ShardingJdbc 与 mybatis plus实现分库分表及读写分离

    本文为博主原创,未经允许不得转载: 目录: 一. 官网及git 地址 二. Apache ShardingSphere 简介 三.spring boot + mybaits plus +shardin ...

  7. 当ChatGPT遇上了CoT

    最近在看CoT(Chain-of-Thought,思维链)方面的论文<Chain-of-Thought Prompting Elicits Reasoning in Large Language ...

  8. 【TouchGFX 】使用 CubeMX 创建 TouchGFX 工程时 LCD 死活不显示

    生成的代码死活无法让LCD显示,经两个晚上的分析验证是LTDC_CLK引脚速度设置为低速导致,经测试中速.高速.超高速都正常,真是冤,聊以此以示纪念

  9. 【java】 向上转型的运用

    应用 :求面积 1,抽象类  Geometry . public abstract class Geometry { public abstract double getArea(); } 2,矩形 ...

  10. Spring————IOC入门学习

    Spring----入门学习 简介 优点 Spring是一个开源的免费的框架(容器)! Spring是一个轻量级,非入侵式的框架 控制反转(IOC),面向切面编程(AOP) 支持对事务的处理,对框架整 ...