C++ socket编程 实现服务端与客户端的双向TCP通讯_vc++ csocket有连接tcp通信-程序员宅基地

技术标签: Socket通信  TCP  C++  C++通信  

运行环境:VS2015

基于https://blog.csdn.net/orange_xxx/article/details/7276868做出了简单修改,可以完全实现双向的数据通信;

TCP通信流程

【来自https://blog.csdn.net/u012801153/article/details/79363575

Server步骤:

  1. 加载套接字库,创建套接字(WSAStartup()/socket());
  2. 绑定套接字到一个IP地址和一个端口上(bind());
  3. 将套接字设置为监听模式等待连接请求(listen());
  4. 请求到来后,接受连接请求,返回一个新的对应于此次连接的套接字(accept());
  5. 用返回的套接字和客户端进行通信,接收来自client的信息(recv()),发送回复信息至client(send());
  6. 返回,等待另一连接请求;
  7. 关闭套接字,关闭加载的套接字库(closesocket()/WSACleanup())。

Client步骤:

  1. 加载套接字库,创建套接字(WSAStartup()/socket());
  2. 绑定套接字到一个IP地址和一个端口上(bind());
  3. 向服务器发出连接请求(connect());
  4. 和服务器端进行通信,发送请求信息至server(send());接收server的回复信息(recv());
  5. 关闭套接字,关闭加载的套接字库(closesocket()/WSACleanup())。

github代码:https://github.com/jiangxinyiba/NetworkCommu_demo/tree/master

服务端代码Server.cpp:

#include "winsock2.h"
#include <WS2tcpip.h>
#include <iostream>
 
#pragma comment(lib, "ws2_32.lib") // load the dll of winsock
using namespace std;

int main(int argc, char* argv[])
{
	const int BUF_SIZE = 64;
	WSADATA			wsd;			    //WSADATA PARAM
	SOCKET			sServer;		    //Server Socket
	SOCKET			sClient;		    //Client Socket
	SOCKADDR_IN		servAddr;		    //Server Addr
	SOCKADDR_IN     clientAddr;         //Client Addr
	SOCKADDR_IN     connect_Addr;       //the Addr that connect this socket (in this demo, connect_Addr = clientAddr)
	int             connectClientlen = sizeof(connect_Addr);
	char			bufSend[BUF_SIZE];	//the buffer area of data-send
	char			bufRecv[BUF_SIZE];  //the buffer area of data-recv
	int				retVal;			    //return value
	char*			closeSymbol = "0";  //symbol of closing communication
	char*           bufReq = "Request Reply";  // symbol of Request Reply
	char            str[INET_ADDRSTRLEN];

    // Server Addr
	servAddr.sin_family = AF_INET;
	inet_pton(AF_INET, "127.0.0.1", (void*)&servAddr.sin_addr.S_un.S_addr);
	servAddr.sin_port = htons((short)5000);

	// Client Addr
	clientAddr.sin_family = AF_INET;
	inet_pton(AF_INET, "127.0.0.1", (void*)&clientAddr.sin_addr.S_un.S_addr);
	clientAddr.sin_port = htons((short)4999);

	// Initialize the dll of winsock
	if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0)
	{
		cout << "WSAStartup failed !" << endl;
		return 1;
	}

	// Create the Server socket 
	sServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (INVALID_SOCKET == sServer)
	{
		cout << "socket failed!" << endl;
		WSACleanup();			 
		return  -1;
	}
	else
	{
		cout << "Server TCP Socket init!" << endl;
	}

	// Bind the IP and Port on Server Socket 
	retVal = bind(sServer, (LPSOCKADDR)&servAddr, sizeof(SOCKADDR_IN));
	if (SOCKET_ERROR == retVal)
	{
		cout << "bind failed!" << endl;
		closesocket(sServer);
		WSACleanup();
		Sleep(5000);
		return -1;
	}
	else
	{
		cout << "Server TCP Socket bind IP & Port !" << endl;
		cout << "Server Address = " << inet_ntop(AF_INET, &servAddr.sin_addr, str, sizeof(str)) << ":" << ntohs(servAddr.sin_port) << endl;
	}

	// Listen the Server socket 
	retVal = listen(sServer, 10);
	if (0 == retVal)
	{
		cout << "Server Socket is listening !" << endl;
	}
	else if (SOCKET_ERROR == retVal)
	{
		cout << "listen failed!" << endl;
		closesocket(sServer);	 
		WSACleanup();	
		Sleep(5000);
		return -1;
	}

	cout << "Server Socket is waiting accpetion !" << endl;
	sClient = accept(sServer, (sockaddr FAR*)&connect_Addr, &connectClientlen);
	if (INVALID_SOCKET == sClient)
	{
		cout << "accept failed!" << endl;
		closesocket(sServer);	
		WSACleanup();
		Sleep(5000);
		return -1;
	}
	else
	{
		cout << "Server get connection with client socket: [" << inet_ntop(AF_INET, &connect_Addr.sin_addr, str, sizeof(str)) << ":" << ntohs(connect_Addr.sin_port) << "]" << endl;
	}

	// loop for the data from the accpeted socket/send the data to the socket 
	while (TRUE) 
	{
		// Initialize the buffer 
		ZeroMemory(bufRecv, BUF_SIZE);

		// Recevice the buffer data from the client 
		retVal = recv(sClient, bufRecv, BUF_SIZE, 0);
		if (SOCKET_ERROR == retVal)
		{
			continue;
		}

		// Check the data from client 
		bufRecv[retVal] = '\0';			// Set the last bit as \0 to avoid the wrong data  
		cout << "Data recv from Client Socket [" << inet_ntop(AF_INET, &connect_Addr.sin_addr, str, sizeof(str)) << ":" << ntohs(connect_Addr.sin_port) << "] : " << bufRecv << endl;
		// When the data from client is ‘0’,exit the loop and finish TCP Communication
		if (!strcmp(bufRecv, closeSymbol))
		{
			cout << "Client Socket wants to finish this communication" << endl;
			closesocket(sServer);
			WSACleanup();
			Sleep(5000);
			break;
		}
		else
		{
			// Automatically send the request reply to client  
			send(sClient, bufReq, strlen(bufReq), 0);
		}
	}
	// Exit
	closesocket(sServer);	 
	WSACleanup();			 
	Sleep(5000);
	return 0;
}

客户端代码Client.cpp:

// Client.cpp : Defines the entry point for the console application.
#include "winsock2.h"
#include <WS2tcpip.h>
#include <iostream>
#pragma comment(lib, "ws2_32.lib")

#define _WINSOCK_DEPRECATED_NO_WARNINGS

using namespace std;

int main(int argc, char* argv[])
{
	const int BUF_SIZE = 64;
	WSADATA			wsd;			    //WSADATA Param
	SOCKET			sClient;		    //Server Socket 
	SOCKADDR_IN		servAddr;		    //Server Addr 
	SOCKADDR_IN     clientAddr;         //Client Addr
	SOCKADDR_IN     send_Data_Addr;     //the Addr that send the data(in this demo, send_Data_Addr = servAddr)
	int				nAddrLen = sizeof(clientAddr);
	int				nAddrLen_s = sizeof(servAddr);
	char			bufSend[BUF_SIZE];	//the buffer area of data-send
	char			bufRecv[BUF_SIZE];  //the buffer area of data-recv
	int				retVal;			    //return value
	char*			closeSymbol = "0";  //symbol of close

    // Server Addr
	servAddr.sin_family = AF_INET;
	inet_pton(AF_INET, "127.0.0.1", (void*)&servAddr.sin_addr.S_un.S_addr);
	servAddr.sin_port = htons((short)5000);
	int	nServAddlen = sizeof(servAddr);

	// Client Addr
	clientAddr.sin_family = AF_INET;
	inet_pton(AF_INET, "127.0.0.1", (void*)&clientAddr.sin_addr.S_un.S_addr);
	clientAddr.sin_port = htons((short)4999);
	int	nClientAddlen = sizeof(clientAddr);

	// Initialize the dll of winsock
	if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0)
	{
		cout << "WSAStartup failed!" << endl;
		return -1;
	}

	// Create the Server socket 
	sClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (INVALID_SOCKET == sClient)
	{
		cout << "Socket failed !" << endl;
		WSACleanup();       
		Sleep(5000);
		return  -1;
	}
	else
	{
		cout << "Client Socket init !" << endl;
	}

	// Bind the client socket with IP and Port 
	retVal = bind(sClient, (LPSOCKADDR)&clientAddr, sizeof(SOCKADDR_IN));
	if (SOCKET_ERROR == retVal)
	{
		cout << "bind failed!" << endl;
		closesocket(sClient);
		WSACleanup();
		Sleep(5000);
		return -1;
	}
	else
	{
		cout << "Client UDP Socket bind IP & Port !" << endl;
		char str[INET_ADDRSTRLEN];
		cout << "Client Address = " << inet_ntop(AF_INET, &clientAddr.sin_addr, str, sizeof(str)) << ":" << ntohs(clientAddr.sin_port) << endl;
	}

	// client request connect server socket
	retVal = connect(sClient, (LPSOCKADDR)&servAddr, sizeof(servAddr));
	if (SOCKET_ERROR == retVal)
	{
		cout << "Client connect failed!" << endl;
		closesocket(sClient);	 
		WSACleanup();	
		Sleep(5000);
		return -1;
	}
	else
	{
		cout << "Client connect with Server socket" << endl;
	}

	// loop for the data from the connected socket/send the data to the server socket 
	while (true) {
		// Initialize the buffer
		ZeroMemory(bufSend, BUF_SIZE);

		// Send the data from client socket to Server Socket
		cout << "Data send to Server Socket: ";
		cin >> bufSend;
		retVal = send(sClient, bufSend, strlen(bufSend), 0);
		if (SOCKET_ERROR == retVal)
		{
			cout << "Send failed!" << endl;
			closesocket(sClient);	 
			WSACleanup();	
			Sleep(5000);
			return -1;
		}
		// When the data from another socket is ‘0’,exit the loop and finish TCP Communication	
		if (!strcmp(bufSend, closeSymbol))
		{
			cout << "Client Socket wants to finish this communication" << endl;
			break;
		}

		// Receive data from server socket
		retVal = recv(sClient, bufRecv, BUF_SIZE, 0);
		bufRecv[retVal] = '\0';
		cout << "Data recv from Server Socket: " << bufRecv << endl;
	}

	closesocket(sClient);	 
	WSACleanup();		

	Sleep(5000);
	return 0;
}

 


注意事项

  1. inet_pton(AF_INET, "127.0.0.1", (void*)&servAddr.sin_addr.S_un.S_addr);这句话是替代了inet_addr的作用,vs2015里面inet_addr好像不能用了,只能用inet_pton替代,之前需要添加#include <WS2tcpip.h>。这里是单机内两个进程间的通信,最后采用的是127.0.0.1的localhost作为IP地址。

  2. WSAStartup(MAKEWORD(2,2),&wsaData):其中MAKEWORD(2,2)表示使用WINSOCK2版本,wsaData用来存储系统传回的关于WINSOCK的资料;

  3. ZeroMemory(bufSend, BUF_SIZE);   //端口发送数据,需要在每次交互前,把之前的buf数据清空,避免缓冲区冗余;但是不能对这个端口的接受数据的缓冲bufRecv清空;这样会造成永久性的空接受情况。

  4. retVal = recv(sClient, bufRecv,BUF_SIZE , 0);   //端口接受另一个端口数据,字符位要选择允许的满字符,这里为BUF_SIZE,确保每次都能把另一个端口的数据全都接收到;其中retVal记录了这组数据的长度;

  5. 这里需要注意,不论是客户端还是服务端,recv和send的第一个参数都是sClient,即客户端的socket,即在TCP通信中recv和send函数的第一个参数应该是发起connect连接的socket。

  6. bufRecv[retVal] = '\0';  //每次接受到的数据因为没有初始化,初始结构都是“烫烫烫烫”,在接受到后,会把前面的若干位变成接受的数据,但是后面还是都为烫,因此需要这个语句将接受数据的缓冲收尾,接受有效的前面若干位数据,剔除烫烫烫烫。

  7. 最后通过输入0来结束本次通信,若客户端发送了一个"0",那就表示需要结束本次通信,两个进程会在5秒内自动关闭。

  8. 两个代码分别放于两个项目中,先运行启动服务端代码,然后运行客户端代码,就可以进行本机的两端通信调试。若先启动了客户端,由于代码保护,一旦客户端无法找到可以连接的服务端,客户端会马上关闭;而先打开服务端的话,服务端会一直处于等待连接状态。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/nandejxy/article/details/82874606

智能推荐

开源:VS.NET打印思想与2003/5DataGrid、DataGridView及二维数据如ListView等终极打印实现_vb.net dategridview横向打印-程序员宅基地

文章浏览阅读1k次。前言  当.NET时代到来时,我们在高兴激动的时候,把自己的系统升级到.NET或是用它开发新的系统。  打印--管理信息系统永恒的话题。于是,我们在开发业务系统的时候不得不再专门做一个打印组件或是购买一个中间件完成单据合同、清单、文档、工资单、报表等等的打印。在开始之前,如果您还想了解更多关于打印的信息,可以查看我曾经写的一篇技术文档:NET环境下有关打印页面设置、打印机设置、打印预览_vb.net dategridview横向打印

C++多线程之创建线程及运行_c++ 创建一个线程并执行-程序员宅基地

文章浏览阅读554次,点赞10次,收藏9次。【代码】C++多线程之创建线程及运行。_c++ 创建一个线程并执行

Bigemap如何添加谷歌图源?-程序员宅基地

文章浏览阅读1.2k次。Arcgis : https://livingatlas.arcgis.com/wayback 包含:卫星影像、历史影像。原文链接:https://blog.csdn.net/kiko677/article/details/133324051。mapbox: https://www.mapbox.com/contribute/ 包含:卫星影像、电子地图。必应地图(bing):http://cn.bing.com/maps 包含:卫星影像、电子地图、地形图。谷歌卫星地图(有偏移)_谷歌图源

AI识别教程 yolov5 穿越火线,csgo等FPS游戏识别,角色识别-程序员宅基地

文章浏览阅读1.2k次,点赞37次,收藏14次。我们本次只是识别穿越火线中的人物,还没有实现自动瞄准,我只用了一百张图片进行预测,预测效果不是很好,你可以增加些图片进行训练。后期还会更新!!!!!!!!!!!!!!!!!!!

MySQL远程操作记录删除_解决MySQL不允许从远程访问-程序员宅基地

文章浏览阅读289次。1。 改表法。可能是你的帐号不允许从远程登陆,只能在localhost。这个时候只要在localhost的那台电脑,登入mysql后,更改 "mysql" 数据库里的 "user" 表里的 "host" 项,从"localhost"改称"%"mysql -u root -pvmwaremysql>use mysql;mysql>update user set host = '%' wh..._远程数据库删除表需要验证

FPGA虚拟化:突破次元壁的技术-程序员宅基地

文章浏览阅读1.2k次。Maxeler还提供了一种类似于Java的编程语言,称为MaxJ,用来对数据流图进行描述和建模。然后通过对应的编译器MaxCompiler,将数据流图映射到底层的FPGA硬件平台,从而对上层用户虚拟化了底层电路逻辑的具体实现。目前,这套数据流引擎架构已经被用在多个高性能计算的应用场景,比如蒙特卡洛仿真、金融风险计算、科学计算,以及一些新兴的应用场景,如卷积神经网络(CNN)的硬件加速等等。在虚拟化框架协议方面的另一个主要工作是对MapReduce框架的FPGA支持。MapReduce是Google提_fpga虚拟化

随便推点

【Notepad】NotepadFree安装Json格式化插件-程序员宅基地

文章浏览阅读217次,点赞10次,收藏4次。Jsonviewer2.dll(64位): https://github.com/zbeboy/Jsonviewer2/releases。NPPJSONViewer.dll(32位): https://github.com/kapilratnani/JSON-Viewer。4、选中要格式化的JSON文本,点击 插件->JSON Viewer->Format JSON。3、重启notepad++软件,插件安装成功。2、在plugins文件夹下创建一个和插件。_notepadfree

预训练模型相对位置编码和绝对位置编码的通俗理解_为什么用相对位置embedding,为什么不直接用0,1,2…-程序员宅基地

文章浏览阅读836次,点赞2次,收藏3次。上图中以第5个位置(索引为4)的单词为中心,那么其左边的单词的编号为:-1,-2,-3,-4,右边的单词的编号为:+1,+2,+3,+4。对于第一个位置的单词“I”,当transformer计算“I”跟“therefore”的attention信息时候,"therefore"会采用第6个位置编码,因为我们是以第4个索引为中心,“therefore”是位于“I”的右边相对于“I”的相对距离为2,所以其采用的是第6个embedding向量。1.作者认为超出范围的位置还采用精准的位置编码时没必要的。_为什么用相对位置embedding,为什么不直接用0,1,2…

笔记 unity3d的guad和plane自适应屏幕大小_unity如何让plane随着屏幕大小而改变-程序员宅基地

文章浏览阅读1.7k次。using UnityEngine;using System.Collections;public class planeFitScreen : MonoBehaviour { // Use this for initialization void Start () { Camera cam = Camera.main; float pos = (cam.nearCli..._unity如何让plane随着屏幕大小而改变

联想 Lenovo PWR-G60 无线掌中宝拆机-程序员宅基地

文章浏览阅读909次。从朋友那里弄了台Lenovo PWR-G60,现在已经停产了,淘宝上某店卖的国产WIFI Pineapple貌似就是拿这个刷的,打算出篇DIY教程现在人在外地,编程器、热风枪、烙铁工具啥的都没有,更新可能会比较慢。那位大佬要是知道Telnet密码麻烦告诉一声,我好刷个Breed是的,你没有看错,我就是用神器“掏耳勺”成功撬开外壳的~..._pwr-g60 拆机

CAXA3D实体设计2023安装教程(非常详细)从零基础入门到精通,看完这一篇就够了_caxa2023-程序员宅基地

文章浏览阅读809次,点赞28次,收藏27次。网络安全行业产业以来,随即新增加了几十个网络安全行业岗位︰网络安全专家、网络安全分析师、安全咨询师、网络安全工程师、安全架构师、安全运维工程师、渗透工程师、信息安全管理员、数据安全工程师、网络安全运营工程师、网络安全应急响应工程师、数据鉴定师、网络安全产品经理、网络安全服务工程师、网络安全培训师、网络安全审计员、威胁情报分析工程师、灾难恢复专业人员、实战攻防专业人员…网上虽然也有很多的学习资源,但基本上都残缺不全的,这是我自己录的网安视频教程,上面路线图的每一个知识点,我都有配套的视频讲解。

html 图片加速,35种加速网站访问的最好做法-程序员宅基地

文章浏览阅读665次。最近看了有名的yahoo关于前端性能优化的文章,做了一下笔记。减少HTTP请求减少网页中组件的数量,例如图像,样式表,脚本等。将样式表单和脚本组合成单个文件。CSS Sprites方法,将所有小图标做成一幅图像,设置成背景,用CSS控制具体显示的区域。qq.com中使用的CSS SpritesImage maps方法,将多个连续的图像组成一幅图像,指定图像不同区域不同的表现(链接等)。不建议。使用..._图片加速

推荐文章

热门文章

相关标签