所谓双向数据传输指的是客户端与服务端之间可以无差异的实现数据交互,此类功能实现的核心原理是通过创建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. Ngnix搭建静态网页和安装wordpress

    使用nginx搭建wordpress和静态网站.以下操作均实在ubuntu1604完成. 安装nginx apt install nginx 验证安装是否完成.在浏览器打开127.0.0.1,能够看到 ...

  2. Codeforces Round #623 (Div. 2) A~D题,D题multiset使用

    比赛链接:Here 1315A. Dead Pixel 签到题, 比较四个值 max(max(x, a - 1 - x) * b, a * max(y, b - 1 - y)) 1315B. Home ...

  3. mysql和redis库存扣减和优化

    前言 大流量情况下的库存是老生常谈的问题了,在这里我整理一下mysql和redis应对扣除库存的方案,采用jmeter进行压测. JMETER设置 库存初始值50,线程数量1000个,1秒以内启动全部 ...

  4. 应用 Serverless 化,让业务开发心无旁骛

    我们希望让用户做得更少而收获更多,通过Serverless化,用云就像用电一样简单."张建锋表示,Serverless 让云计算从一种资源真正变成一种能力,未来云将全面 Serverless ...

  5. 阿里云张建锋:核心云产品全面 Serverless 化

    11月3日,2022 杭州 · 云栖大会上,阿里云智能总裁张建锋表示,以云为核心的新型计算体系正在形成,软件研发范式正在发生新的变革,Serverless 是其中最重要的趋势之一,阿里云将坚定推进核心 ...

  6. SpringCloud学习 系列十、服务熔断与降级(2-方法级别服务降级)

    系列导航 SpringCloud学习 系列一. 前言-为什么要学习微服务 SpringCloud学习 系列二. 简介 SpringCloud学习 系列三. 创建一个没有使用springCloud的服务 ...

  7. kafka集群七、java操作kafka(有密码验证)

    系列导航 一.kafka搭建-单机版 二.kafka搭建-集群搭建 三.kafka集群增加密码验证 四.kafka集群权限增加ACL 五.kafka集群__consumer_offsets副本数修改 ...

  8. 机器学习-线性回归-损失函数+正则化regularization-06

    目录 1. 为什么要加上正则项 2 L1稀疏 L2平滑 3. 代码1--L2正则 4 代码2--L2正则2 5. 代码3--l1正则 6. ElasticNet 1. 为什么要加上正则项 防止模型的过 ...

  9. 文心一言 VS 讯飞星火 VS chatgpt (183)-- 算法导论13.4 7题

    七.用go语言,假设用 RB-INSERT 将一个结点 x 插入一棵红黑树,紧接着又用 RB-DELETE 将它从树中删除.结果的红黑树与初始的红黑树是否一样?证明你的答案. 文心一言: 首先,我们需 ...

  10. 分享Go书籍-《Go Web编程》

    大家好,我是沙漠尽头的狼. 最近几天在看一本Go的书籍,看了100来页,感觉不错,分享给大家​.​ 书籍基本信息 书籍信息: 书名:Go Web编程 作 者:(新加坡)郑兆雄(Sau Sheong C ...