所谓双向数据传输指的是客户端与服务端之间可以无差异的实现数据交互,此类功能实现的核心原理是通过创建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. 用 Python 开发了一个 PDF 抽取Excel表格的小工具

    大家好哇 从 PDF 里 copy 表格时,粘贴出来后格式都是错乱的.这麻烦事交给 Python 再合适不过里,我开发了一个从 PDF 抽取表格另存为 Excel 文件的应用,我把它部到 huggin ...

  2. Grafana-安装饼状图

    官网:https://grafana.com/grafana/plugins/grafana-piechart-panel/?tab=installation 使用grafana-cli直接安装 [r ...

  3. CS01 BOM客制化屏幕增强

    一.BOM行项目新增定制字段 效果如下 二.前台增强实现步骤 1.行项目表新增字段 2.CMOD,增强项目PCSD0002:在行项目中增强(PCSD0003:在抬头增强) 3.双击创建定制化屏幕 4. ...

  4. C++:如何将 LLVM 嵌套到你的项目中去

    IDE: Clion LLVM cmake_minimum_required(VERSION 3.9) project(clang_demo) find_package(LLVM REQUIRED C ...

  5. vivo 大规模特征存储实践

    本文首发于 vivo互联网技术 微信公众号 链接:https://mp.weixin.qq.com/s/u1LrIBtY6wNVE9lzvKXWjA作者:黄伟锋 本文旨在介绍 vivo 内部的特征存储 ...

  6. springboot线程池的使用方式1

    线程池的创建方法 总共有 7 种,但总体来说可分为 2 类: 一类是通过 ThreadPoolExecutor 创建的线程池: 另一个类是通过 Executors 创建的线程池. 1. Executo ...

  7. Springboot+ELK实现日志系统简单搭建

    前面简单介绍了ELK三剑客中的其中两个Elasticsearch和Kibana的简单使用,如果对这两个不了解,可以看下下面的 Centos7安装Elasticsearch和Kibana 搜索引擎基础- ...

  8. Vue3使用vue-video-player组件

    1.安装依赖(亲测5.0.1版本可用,最新版本会找不到'vue-video-player/src/custom-theme.css'这个样式) yarn add  vue-video-player@5 ...

  9. zzuli 1079

    以EOF结束输入的处理 使用cin.hasNext(),现在还不懂就先记这了 import java.util.Scanner; public class Main{ public static vo ...

  10. Vue第五篇 Vue的生命周期

    Vue生命周期简介 生命周期的钩子函数 <!DOCTYPE html> <html lang="en"> <head> <meta cha ...