首页 > 系统相关 >Windows下使用winsock库实现tcp客户端通信,C/C++

Windows下使用winsock库实现tcp客户端通信,C/C++

时间:2024-03-12 23:35:22浏览次数:20  
标签:WINNT 函数 Windows C++ WIN32 tcp Winsock inet

编程思路

第一步

创建一个WASDATA结构体变量,用于存储关于Winsock库的信息;初始化Winsock库。

第二步

创建TCP套接字。

第三步

创建sockaddr_in结构体变量,用于储存服务器地址信息。里面包括设置地址族、IP地址、端口号。

第四步

调用connect函数连接服务器。

通信

send函数发送数据

recv函数接收数据

实现代码

头文件部分

#include <iostream>
#include <winsock2.h>
#include <ws2tcpip.h>

#pragma comment(lib, "ws2_32.lib") //告诉编译器链接Winsock库

main 函数部分

int main()
{
    WSADATA wsaData; //创建一个结构体变量,用于存储关于Winsock库的信息
    int result = WSAStartup(MAKEWORD(2, 2), &wsaData); //初始化Winsock库,指定版本号2.2,检查返回值
    if (result != 0)
    {
        std::cout << "WSAStartup failed: " << result << std::endl; //输出错误信息并退出程序
        return 1;
    }

    SOCKET connectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //创建一个TCP套接字,检查返回值
    if (connectSocket == INVALID_SOCKET)
    {
        std::cout << "socket failed with error: " << WSAGetLastError() << std::endl; //输出错误信息并退出程序
        WSACleanup(); //清除Winsock库
        return 1;
    }

    sockaddr_in service; //创建一个结构体变量,用于存储服务器地址信息
    service.sin_family = AF_INET; //指定地址族为IPv4
    inet_pton(AF_INET, "127.0.0.1", &service.sin_addr); //将字符串类型的IP地址转换为二进制网络字节序的IP地址,并存储在结构体中
    service.sin_port = htons(6666); //将端口号从主机字节序转换为网络字节序,并存储在结构体中

    result = connect(connectSocket, (SOCKADDR*)&service, sizeof(service)); //连接到服务器,检查返回值
    if (result == SOCKET_ERROR)
    {
        std::cout << "connect failed with error: " << WSAGetLastError() << std::endl; //输出错误信息并退出程序
        closesocket(connectSocket); //关闭套接字
        WSACleanup(); //清除Winsock库
        return 1;
    }

    std::cout << "Connected to server." << std::endl; //连接成功,输出消息

    char sendBuffer[1024] = "Hello, server!"; //创建发送缓冲区,存储待发送的数据
    result = send(connectSocket, sendBuffer, sizeof(sendBuffer), 0); //向服务器发送数据,检查返回值
    if (result == SOCKET_ERROR)
    {
        std::cout << "send failed with error: " << WSAGetLastError() << std::endl; //输出错误信息并退出程序
        closesocket(connectSocket); //关闭套接字
        WSACleanup(); //清除Winsock库
        return 1;
    }

    char recvBuffer[1024]; //创建接收缓冲区,用于存储从服务器接收到的数据
    result = recv(connectSocket, recvBuffer, sizeof(recvBuffer), 0); //从服务器接收数据,检查返回值
    if (result == SOCKET_ERROR)
    {
        std::cout << "recv failed with error: " << WSAGetLastError() << std::endl; //输出错误信息并退出程序
        closesocket(connectSocket); //关闭套接字
        WSACleanup(); //清除Winsock库
        return 1;
    }

    std::cout << "Received message from server: " << recvBuffer << std::endl; //输出从服务器收到的数据

    closesocket(connectSocket); //关闭套接字
    WSACleanup(); //清除Winsock库

    return 0;
}

注意事项(debug过程)

运行代码之前要使用网络调试助手打开TCP服务端,注意端口号、IP地址这些要匹配。

代码主要是C语言,C++部分是控制台输入输出的,如果纯C语言就include<stdio.h>,用printfscanf这些库函数替换就好了。

以上代码使用VS的编译器上是可以直接运行的,但是如果是使用MinGW gcc/g++就会出现问题。我们来看报错。

1.inet_pton函数未定义。

inet_pton函数将点分十进制串转换成网络字节序二进制值,此函数对IPv4地址和IPv6地址都能处理,在Windows下只需包含ws2tcpip.h头文件就行了

根据网上的说法,是因为Windows gcc 默认的 _WIN32_WINNT 是 502 Windows Server 2003,所以解决方案是重新定义_WIN32_WINNT,在ws2tcpip.h前加入

#ifdef  _WIN32_WINNT
#undef  _WIN32_WINNT
#define  _WIN32_WINNT  0x0600
#endif

还有一个方法,那就是。。。不用inet_pton()函数了,用别的IP地址转换函数——inet_addr()

这样第三步的代码改为

    sockaddr_in service; //创建一个结构体变量,用于存储服务器地址信息
    service.sin_family = AF_INET; //指定地址族为IPv4
    service.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); //将点分十进制转化32位unsigned int
    service.sin_port = htons(6666); //将端口号从主机字节序转换为网络字节序,并存储在结构体中

这个问题就解决了。

2. 链接动态库问题undefined reference to __imp_WSAStartup

在vs中直接加入

#pragma comment(lib, "ws2_32.lib")

就可以链接winsock动态库,不知道为什么gcc编译器不行。1 问题解决后,报如下错误:

所以在vscode的配置tasks.json的args参数加一个:"-lwsock32",在编译命令中指定链接就可以了。

对于如果找不到_imp_inet_pton的话,就需要再加args参数:"-lws2_32"

然后就能连上TCP服务器了。

标签:WINNT,函数,Windows,C++,WIN32,tcp,Winsock,inet
From: https://www.cnblogs.com/gofan-SiTu/p/18069624

相关文章

  • 第十四届蓝桥杯C++B组编程题题目以及题解
    a.冶炼金属(二分)思路:设任意一条冶炼记录投入金属数量为a,产出金属为b.对于每一条冶炼记录我们都可以得到一个转换率V的范围:b<=a/v<b+1即a/b<=v<a/(b+1)为什么是b+1呢?因为既然能产出b个金属,也就意味着一定不能产出b+1个,所以a/v<b+1每一条记录都可以得到v的一个区间,我......
  • Windows命令行不加解释器和文件后缀名直接运行Python脚本
    Windows命令行不加解释器和文件后缀名直接运行Python脚本首次编辑:24/2/29/20:30最后编辑:24/2/25/20:44引子都知道Windowscmd中,运行可执行文件和bat时,可以直接输入不带后缀的文件名。rem运行main.exemainrem运行mybat.batmybat而执行python脚本时,却需要指明python作......
  • C++虚继承
    虚继承(VirtualInheritance)为了解决多继承时的命名冲突和冗余数据问题,c++提出了虚继承,使得在派生类中只保留一份间接基类的成员。在继承方式前面加上 virtual 关键字就是虚继承虚继承的目的是让某个类做出声明,承诺愿意共享它的基类。其中,这个被共享的基类就称为虚基类(Virtual......
  • 命令行 要查看在Windows上已安装的所有.NET Framework版本 查看在Windows上已安装的
       要查看在Windows上已安装的所有.NETFramework版本,可以按照以下步骤执行:打开命令提示符(CommandPrompt)或PowerShell。可以通过在Windows搜索栏中键入“cmd”或“PowerShell”来找到并打开这些应用程序。在命令提示符或PowerShell中,输入以下命令并按Enter键:......
  • 小白Windows下通过Ollama部署使用本地模型
    安装环境运行环境为windowsR9000P2021拯救者笔记本AMDR7-5800H32G内存NVIDIARTX3070LaptopGPU安装主程序Ollama下载exe,直接下一步下一步没有设置可以更改windows默认安装路径:C:\Users\wbigo\AppData\Local\Programs\Ollama\安装后会自动将该路径加入环境变量双......
  • 【C++】string类(介绍、常用接口)
    ......
  • C#TCP通讯(二)
    客户端代码:1byte[]ReadBytes=newbyte[1024];2privatevoidConnectServer_Camera(stringip,intport)3{5tcpclient=newTcpClient();6tcpclient.BeginConnect(IPAddress.Parse(ip),port,CameraProcess,null);8}9private......
  • windows、C++怎么看线程在哪个核上运行
    一.要在Windows系统上查看线程运行在哪个处理器核心上,可以使用Windows系统提供的一些工具和方法。在Windows中,可以使用以下几种方式来查看线程运行的处理器核心:使用任务管理器打开任务管理器:可以通过按下 Ctrl+Shift+Esc 组合键快速打开任务管理器,或者通过右键......
  • nodejs集成C++代码:手写简单的addon
    文章目录nodejs与node-gyp手写一个简单的addon编写一个简单的binding.gyp文件编写C++源文件V8版本:addon.ccnapi_api版本:addon_api.cc编译命令JS调用在这个专栏里,已经提到过web系统中c++的两大应用场景了:assembly和cef框架的应用,这两个可以说都是客户......
  • 【华为OD机试】真题B卷-最大花费金额(C++)
    华为OD机试真题汇总目录  【华为OD机试】真题汇总A+B+C+D券(Python实现)  【华为OD机试】真题汇总A+B+C+D卷(JAVA实现)  【华为OD机试】真题汇总A+B+C+D卷(C++实现)一、题目题目描述:双十一众多商品进行打折销售,小明想购买自己心仪的一些物品,但由于受购买资金限制,......