Windows编程(网络编程)

Windows编程(网络编程)套接字类型与协议设置SOCK_STREAM[流套接字]TCP面向连接、可靠的数据传输适合传输大量的数据,不支持广播、多播SOCK_DGRAM[数据包套接字]

大家好,又见面了,我是全栈君,祝每个程序员都可以多学几门语言。

Windows编程(网络编程)

套接字类型与协议设置

SOCK_STREAM[流套接字] TCP

面向连接、可靠的数据传输 适合传输大量的数据,不支持广播、多播

SOCK_DGRAM[数据包套接字] UDP

无连接 支持广播、多播

SOCK_RAW[原始套接字]

可以读写内核没有处理的 IP 数据报

避开 TCP/IP 处理机制,被传送的数据报可以被直接传送给需要它的的应用程序

-引用头文件 winsock2.h

– 导入 ws2_32.lib 库

– window 下 socket 编程都要首先进行 Winsock 的初始化

使用:

SOCKET WSAAPI socket(
  int af,
  int type,
  int protocol
);

af参数:

当前支持的值为 AF_INET 或 AF_INET6,它们是 IPv4 和 IPv6 的 Internet 地址族格式。如果安装了地址族的 Windows 套接字服务提供程序,则支持地址族的其他选项(例如,用于 NetBIOS 的 AF_NETBIOS)。请注意,AF_ 地址族和 PF_ 协议族常量的值是相同的(例如,AF_INETPF_INET),因此可以使用任一常量。

AF_UNSPEC0 地址族未指定。
**AF_INET ** Internet 协议版本 4 (IPv4) 地址族。
AF_IPX IPX/SPX 地址族。仅当安装了 NWLink IPX/SPX NetBIOS 兼容传输协议时才支持此地址系列。Windows Vista 及更高版本不支持此地址系列。
AF_APPLETALK AppleTalk 地址族。仅当安装了 AppleTalk 协议时才支持此地址族。Windows Vista 及更高版本不支持此地址系列。
AF_NETBIOS NetBIOS 地址族。仅当安装了 NetBIOS 的 Windows 套接字提供程序时才支持此地址族。32 位版本的 Windows 支持 NetBIOS 的 Windows 套接字提供程序。默认情况下,此提供程序安装在 32 位版本的 Windows 上。64 位版本的 Windows 不支持 NetBIOS 的 Windows 套接字提供程序,包括 Windows 7、Windows Server 2008、Windows Vista、Windows Server 2003 或 Windows XP。NetBIOS 的 Windows 套接字提供程序仅支持类型参数设置为SOCK_DGRAM 的套接字。NetBIOS 的 Windows 套接字提供程序与NetBIOS编程接口没有直接关系。Windows Vista、Windows Server 2008 及更高版本不支持 NetBIOS 编程接口。
AF_INET6 Internet 协议版本 6 (IPv6) 地址族。
AF_IRDA 红外数据协会 (IrDA) 地址族。仅当计算机安装了红外端口和驱动程序时,才支持此地址族。
AF_BTH 蓝牙地址族。如果计算机安装了蓝牙适配器和驱动程序,则 Windows XP SP2 或更高版本支持此地址系列。

type参数:

新套接字的类型规范。

套接字类型的可能值在Winsock2.h头文件中定义。

在 Windows Sockets 1.1 中,唯一可能的套接字类型是SOCK_DGRAMSOCK_STREAM

类型 意义
SOCK_STREAM 一种套接字类型,通过 OOB 数据传输机制提供有序的、可靠的、双向的、基于连接的字节流。此套接字类型使用 Internet 地址族(AF_INET 或 AF_INET6)的传输控制协议 (TCP)。
SOCK_DGRAM 支持数据报的套接字类型,数据报是固定(通常很小)最大长度的无连接、不可靠的缓冲区。此套接字类型使用 Internet 地址族(AF_INET 或 AF_INET6)的用户数据报协议 (UDP)。
SOCK_RAW 提供原始套接字的套接字类型,允许应用程序操作下一个上层协议标头。要操作 IPv4 标头,必须在套接字上设置IP_HDRINCL套接字选项。要操作 IPv6 标头,必须在套接字上设置IPV6_HDRINCL套接字选项。
SOCK_RDM 提供可靠消息数据报的套接字类型。这种类型的一个例子是 Windows 中的实用通用多播 (PGM) 多播协议实现,通常称为可靠多播编程。仅当安装了可靠多播协议时才支持此类型值。
SOCK_SEQPACKET 一种基于数据报提供伪流数据包的套接字类型。

protocol参数

要使用的协议。协议参数的可能选项特定于指定的地址族和套接字类型。协议的可能值在Winsock2.hWsrm.h头文件中定义 。

在为 Windows Vista 及更高版本发布的 Windows SDK 上,头文件的组织已更改,此参数可以是Ws2def.h头文件中定义的IPPROTO枚举类型的值之一。请注意,Ws2def.h头文件自动包含在Winsock2.h 中,不应直接使用。

如果指定值为 0,则调用者不希望指定协议,服务提供者将选择要使用的协议

af参数为 AF_INET 或 AF_INET6 且类型SOCK_RAW 时,在 IPv6 或 IPv4 数据包头的协议字段中设置为协议指定的值。

协议 意义
IPPROTO_ICMP Internet 控制消息协议 (ICMP)。当af参数为AF_UNSPECAF_INETAF_INET6并且类型参数为SOCK_RAW或未指定时,这是一个可能的值。Windows XP 及更高版本支持此协议值。
IPPROTO_IGMP Internet 组管理协议 (IGMP)。当af参数为AF_UNSPECAF_INETAF_INET6并且类型参数为SOCK_RAW或未指定时,这是一个可能的值。Windows XP 及更高版本支持此协议值。
BTHPROTO_RFCOMM 蓝牙射频通信 (Bluetooth RFCOMM) 协议。当af参数为AF_BTH类型参数为SOCK_STREAM时,这是一个可能的值。带有 SP2 或更高版本的 Windows XP 支持此协议值。
IPPROTO_TCP 传输控制协议 (TCP)。当af参数为AF_INETAF_INET6并且类型参数为SOCK_STREAM时,这是一个可能的值。
IPPROTO_UDP 用户数据报协议 (UDP)。当af参数是AF_INETAF_INET6并且类型参数是SOCK_DGRAM时,这是一个可能的值。
IPPROTO_ICMPV6 Internet 控制消息协议版本 6 (ICMPv6)。当af参数为AF_UNSPECAF_INETAF_INET6 并且类型参数为SOCK_RAW或未指定时,这是一个可能的值。Windows XP 及更高版本支持此协议值。
IPPROTO_RM 用于可靠组播的 PGM 协议。当af参数是AF_INET并且类型参数是SOCK_RDM时,这是一个可能的值。在为 Windows Vista 及更高版本发布的 Windows SDK 上,此协议也称为IPPROTO_PGM。仅当安装了可靠多播协议时才支持此协议值。

Windows编程(网络编程)

TCP 通讯

SOCKADDR_IN

原型:

typedef struct sockaddr_in {


    USHORT sin_port;//16 位地址类型
    IN_ADDR sin_addr;//16 位端口号 65535 2 的 16 次方
    CHAR sin_zero[8];//8 字节填充
} 

IN_ADDR:

#define s_addr  S_un.S_addr /* can be used for most tcp & ip code */
#define s_host  S_un.S_un_b.s_b2    // host on imp
#define s_net   S_un.S_un_b.s_b1    // network
#define s_imp   S_un.S_un_w.s_w2    // imp
#define s_impno S_un.S_un_b.s_b4    // imp #
#define s_lh    S_un.S_un_b.s_b3    // logical host

Windows编程(网络编程)

Server端

代码实例:

#include <WinSock2.h>
#include <Windows.h>
#include <iostream>
#include<stdio.h>
#pragma warning(disable:4996)
#pragma comment(lib, "ws2_32.lib")
using namespace std;



int main() {


	//1 初始化网络库
	// 加载套接字库 
	WORD wVersionRequested; WSADATA wsaData; 
	int err; wVersionRequested = MAKEWORD(2, 2); 
	// 1、初始化套接字库
	err = WSAStartup(wVersionRequested, &wsaData);
	if (err != 0) { printf("WSAStartup errorNum = %d\n", GetLastError());
	return err; 
	}
	if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
		printf("LOBYTE errorNum = %d\n", GetLastError()); 
		WSACleanup();
		return -1;
	}
	SOCKET sockSrv = socket(AF_INET, SOCK_STREAM, 0);
	if (INVALID_SOCKET == sockSrv) { 
		printf("socket errorNum = %d\n", GetLastError());
		return -1; 
	}



	SOCKADDR_IN addrSrv;
	addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);//任意地址连接
	addrSrv.sin_family = AF_INET; //设置ipv4
	addrSrv.sin_port = htons(6001); //设置端口
	if (SOCKET_ERROR == bind(sockSrv, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR))) {
		printf("bind errorNum = %d\n", GetLastError()); return -1;
	}
	if (SOCKET_ERROR == listen(sockSrv, 5)) {
		printf("listen errorNum = %d\n", GetLastError()); return -1; 
	}
	SOCKADDR_IN addrCli;
	int len = sizeof(SOCKADDR);
 while (TRUE) { 
		
		SOCKET sockConn = accept(sockSrv, (SOCKADDR*)&addrCli, &len);//创建socket并进行阻塞
		char sendBuf[100] = { 0 }; 
		sprintf_s(sendBuf, 100, "Welcome %s to bingo!", inet_ntoa(addrCli.sin_addr));
		//发送数据
		int iLen = send(sockConn, sendBuf, strlen(sendBuf) + 1, 0);
		if (iLen < 0) { 
			printf("send errorNum = %d\n", GetLastError()); return -1;
		}
		char recvBuf[100] = {0}; 
		iLen = recv(sockConn, recvBuf, 100, 0); //接收数据
		if (iLen < 0) {
			printf("recv errorNum = %d\n", GetLastError());
			return -1; }//打印接收的数据 
		printf("recvBuf = %s\n", recvBuf);
		closesocket(sockConn); 
	
	}


}

创建Socket后调用bind()绑定本机监听地址。并且listen()设置监听连接请求。accept()接受请求,并且进行阻塞。如果有会话连接过来可以调用recv()send()进行接受和发送数据。

Client端

#include<iostream>
#include<WinSock2.h>
#include<stdio.h>
#pragma warning(disable:4996)
#pragma comment(lib, "ws2_32.lib")
using namespace std;
#include<Windows.h>

#include<stdlib.h>

int main() {
	printf("Client\n"); 
	char sendBuf[] = "hello,world";
	//1 初始化网络库 // 加载套接字库
	WORD wVersionRequested;
	WSADATA wsaData; int err; 
	wVersionRequested = MAKEWORD(2, 2); 
	// 1、初始化套接字库 
	err = WSAStartup(wVersionRequested, &wsaData); 
	if (err != 0)
	{
		printf("WSAStartup errorNum = %d\n", GetLastError());
		return err; 
	}
	if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
	{
		printf("LOBYTE errorNum = %d\n", GetLastError()); WSACleanup();
		return -1; }
	
	// 新建套接字
	SOCKET socket_cli = socket(AF_INET, SOCK_STREAM,0);
	if (INVALID_SOCKET == socket_cli) {
		cout << "Error" << endl;
		return -1;


	}
	SOCKADDR_IN addrSrv;
	addrSrv.sin_addr.S_un.S_addr = inet_addr("192.168.8.104");
	addrSrv.sin_port = htons(6001);
	addrSrv.sin_family = AF_INET;
	cout << "test" << endl;
	if (connect(socket_cli, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR)) == SOCKET_ERROR) {

		
		return -1;
	}
	// 4 接收和发送数据
	char recvBuf[100] = { 0 };
	int iLen = recv(socket_cli, recvBuf, 100, 0);
	if (iLen < 0) {
		printf("recv errorNum = %d\n", GetLastError());
		return -1;
	}

	printf("Client recvBuf = %s\n", recvBuf);
	iLen = send(socket_cli, sendBuf, strlen(sendBuf) + 1, 0);
	if (iLen < 0) {
		printf("send errorNum = %d\n", GetLastError());
		return -1;
	} 
	closesocket(socket_cli);
	WSACleanup();
		return 0;
	
}

UDP通讯

Windows编程(网络编程)

Server端

#include<iostream>
#include<WinSock2.h>
#include<stdio.h>
#pragma warning(disable:4996)
#pragma comment(lib, "ws2_32.lib")
using namespace std;
#include<Windows.h>

#include<stdlib.h>

int main() {

	 // 初始化套接字库 
	WORD wVersion; WSADATA wsaData;
	int err; wVersion = MAKEWORD(1, 1); 
	err = WSAStartup(wVersion, &wsaData); 
	if (err != 0) {
		return err;
}
	if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) { WSACleanup(); return -1;
	}// 创建套接字 
	SOCKET sockSrv = socket(AF_INET, SOCK_DGRAM, 0); 
	cout << "socket创建成功" << endl;
	SOCKADDR_IN addrSrv;
	addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
	addrSrv.sin_family = AF_INET; 
	addrSrv.sin_port = htons(6003);
	// 绑定套接字
	bind(sockSrv, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));
	// 等待并接收数据 
	SOCKADDR_IN addrCli;
	int len = sizeof(SOCKADDR_IN);
	char recvBuf[100];
	char sendBuf[100];

	while (true) { 
		std::cout << "循环" << std::endl;

		recvfrom(sockSrv, recvBuf, 100, 0, (SOCKADDR*)&addrCli, &len);
		std::cout << recvBuf << std::endl; 
		sprintf_s(sendBuf, 100, "Ack %s", recvBuf);
		sendto(sockSrv, sendBuf, strlen(sendBuf) + 1, 0, (SOCKADDR*)&addrCli, len); 
	}closesocket(sockSrv);
	WSACleanup();
	system("pause");
	return 0;
    
}

Client端:

int main() {

	{ // 加载套接字库 
		WORD wVersion; 
		WSADATA wsaData;
		int err; wVersion = MAKEWORD(1, 1); 
		err = WSAStartup(wVersion, &wsaData); 
		if (err != 0) {
			return err;
		}if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) { 
			WSACleanup(); return -1; }
		// 创建套接字 
		SOCKET sockCli = socket(AF_INET, SOCK_DGRAM, 0); 
		SOCKADDR_IN addrSrv;
		addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
		addrSrv.sin_port = htons(6001); 
		addrSrv.sin_family = AF_INET; 
		int len = sizeof(SOCKADDR); char sendBuf[] = "hello"; 
		char recvBuf[100]; //发送数据
		sendto(sockCli, sendBuf, strlen(sendBuf) + 1, 0, (SOCKADDR*)& addrSrv, len);
		recvfrom(sockCli, recvBuf, 100, 0, (SOCKADDR*)& addrSrv, &len); 
		std::cout << recvBuf << std::endl;
		closesocket(sockCli); 
		system("pause"); return 0; }
}

TCP与UDP适用场景

Windows编程(网络编程)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/119857.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • MFC 键盘钩子「建议收藏」

    MFC 键盘钩子「建议收藏」一、前言一日,看见我妈正在用电脑练习打字,频频低头看键盘,我想:要是键盘能发音的话,不就可以方便她养成”盲打”的好习惯吗?光想不做可不行,开始行动(您可千万别急着去拿工具箱啊^_^)…按键能发音,其关键就是让程序能够知道当前键盘上是哪个键被按下,并播放相应的声音,自己的程序当然不在话下,那么其它程序当前按下哪个键如何得知呢?利用键盘钩子便可以很好地解决。下载本文的全部源代码大

    2022年6月7日
    53
  • 用vscode写博客和发布

    用vscode写博客和发布

    2021年9月14日
    72
  • Android P版本应用兼容性适配技术指导「建议收藏」

    ndroidP版本中伴随很多机制和新增特性的改变,对自研以及第三方应用带来了很多兼容性问题。本文档第1章主要介绍谷歌P版本开发环境搭建以及调试;第2章节主要是对P版本兼容性现状一些摸底测试情况以及问题分类;第3章节主要是P版本一些特性介绍以及应用适配P版本的一些开发指导。1. AndroidP背景1.1AndroidP版本里程碑Preview1 (initialrelease,alp…

    2022年4月10日
    37
  • 三极管开关电路_利用三极管设计开关电路[通俗易懂]

    三极管开关电路_利用三极管设计开关电路[通俗易懂]很多工程师在上学时被老师讲的三极管的各种电路接法,和小信号模型分析给绕晕了。而且大学的课本大多数都是在讲三极管的放大特性。其实在实际的电路设计中,三极管的很多应用场景只是利用三级管的开关特性,我们往往是运用三极管来实现开关电路,做一些电平转换的功能。这是由于两个原因造成的:由于数字电路的快速发展,模拟电路设计的比重越来越小;另外运算放大器,越来越便宜,各项特性也比分立器件实现的放大电路相…

    2022年9月20日
    0
  • python下载步骤-python安装教程详解|python下载安装教程步骤「建议收藏」

    python下载步骤-python安装教程详解|python下载安装教程步骤「建议收藏」Python是现在最受欢迎的编程语言,使用Python开发软件应用效率极高,相比其它语言有不可比拟的优势,Python是一种跨平台的计算机程序设计语言。免费开源、最初被设计用于编写自动化脚本(shell),随着版本的不断更新和语言新功能的添加,越来越多被用于独立的、大型项目的开发,它是一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言,今天小编分享的是Windows下安装python教…

    2022年5月20日
    31
  • 远程调试部署在容器中的springboot项目「建议收藏」

    远程调试部署在容器中的springboot项目「建议收藏」问题:访问网站,会根据ip判断访客所处位置,但部分ip插入数据库失败。 以为是一次小问题,很快就解决了,没想到最终花了6个小时左右,才搞清楚。分析 :1、将本地程序跑起来,发现一切正常,可以插入到数据库。但问题在线上确实妥妥的出现的,而我现在日志级别是info,没有错误日志。所有准备Debug线上程序,之前只debug过使用基本的tomcat发布。而我现在的jar是使用docker构建的镜像,运行的镜像。 2、问题从线上转化到了,我需要远程debug线上程序发现问题,并将之解决。查各种资料,配置

    2022年6月13日
    25

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号