MFC 网络编程 -- 总结
原文链接:http://www.cnblogs.com/lidabo/archive/2012/07/19/2598734.html
1.基于 TCP 的 socket 编程
/* 服务器端程序流程: 1.加载套接字库 WSAStartup 2.创建套接字 socket 3.将我们创建的套接字,绑定到本机地址的某一端口上 bind 4.为套接字设置监听模式,准备客户请求 listen 5.等待客户请求到来。当请求到来,将接受连接请求,并返回一个新的对应于此次连接的套接字 accept 6.用新返回的套接字和客户端进行通信 send / recv 7.在通信结束后,关闭套接字 closesocket客户端程序流程: 1.加载套接字库 WSAStartup 2.创建套接字 socket 3.向服务器发出请求连接 connect 4.和服务器进行通信 send / recv 5.在通信结束后,关闭套接字 closesocket */
服务器端代码:
#include <Winsock2.h> #include <stdio.h> #pragma comment(lib, "Ws2_32.lib") void main() { // 加载套接字库,并进行套接字的版本协商 WORD wVersionRequested; // 指定将要加载的 winsock 库版本 WSADATA wsaData; // 用于存储加载的 winsock 库版本信息 int result; // 用于检测 WSAStartup 函数运行结果 wVersionRequested = MAKEWORD(1, 1); // 设定版本 result = WSAStartup(wVersionRequested, &wsaData); // 函数 WSAStartup 调用成功返回 0 // 出错处理 if (result != 0) { return; } if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) { WSACleanup(); return; } // 创建套接字 SOCKET sock = socket(AF_INET, SOCK_STREAM, 0); // 绑定套接字 SOCKADDR_IN addrInfo; // 存储本地主机地址信息 addrInfo.sin_addr.S_un.S_addr = htonl(INADDR_ANY); // 本地主机地址 addrInfo.sin_port = htons(6000); // 端口号 addrInfo.sin_family = AF_INET; // 地址族 bind(sock, (SOCKADDR *)&addrInfo, sizeof(SOCKADDR)); // 设置套接字监听模式 listen(sock, 5); SOCKADDR_IN addrInfoClient; // 存储客户端地址信息 int len = sizeof(SOCKADDR); while (true) { // 等待客户请求到来,并返回用于通信的套接字 SOCKET sockConnect = accept(sock, (SOCKADDR *)&addrInfoClient, &len); // 下面通过刚建立的套接字,来进行通信 // 发送数据 char sendBuf[100]; sprintf(sendBuf, "这是服务器端,主机地址:%s", inet_ntoa(addrInfo.sin_addr)); send(sockConnect, sendBuf, strlen(sendBuf), 0); // 接收数据 char recvBuf[100]; recv(sockConnect, recvBuf, strlen(recvBuf), 0); // 打印接收的数据 printf("%s\n", recvBuf); closesocket(sockConnect); } }
客户端代码:
#include <Winsock2.h> #include <stdio.h> #pragma comment(lib,"Ws2_32.lib") void main() { // 加载套接字库,并进行套接字的版本协商 WORD wVersionRequested; // 指定将要加载的 winsock 库版本 WSADATA wsaData; // 用于存储加载的 winsock 库版本信息 int result; // 用于检测 WSAStartup 函数运行结果 wVersionRequested = MAKEWORD(1, 1); // 设定版本 result = WSAStartup(wVersionRequested, &wsaData); // 函数 WSAStartup 调用成功返回 0 // 出错处理 if (result != 0) { return; } if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) { WSACleanup(); return; } // 创建套接字 SOCKET sockConnect = socket(AF_INET, SOCK_STREAM, 0); // 向服务器发出连接请求 SOCKADDR_IN addrInfoServer; // 存储服务器端地址信息 addrInfoServer.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); addrInfoServer.sin_port = htons(6000); addrInfoServer.sin_family = AF_INET; // 向服务器发出连接请求 connect(sockConnect, (SOCKADDR *)&addrInfoServer, sizeof(SOCKADDR)); // 接收数据 char recvBuf[100]; recv(sockConnect, recvBuf, sizeof(recvBuf), 0); printf("%s\n", recvBuf); // 发送数据 char sendBuf[100] = "这是客户端\n"; send(sockConnect, sendBuf, sizeof(sendBuf) + 1, 0); //关闭套接字 closesocket(sockConnect); WSACleanup(); system("pause"); return; }
2. 基于 UDP 无连接的 socket 编程
/*服务端程序流程: 1.加载套接字库 WSAStartup 2.创建套接字 socket 3.将创建的套接字绑定到一个本地地址和端口上 bind 4.等待接收数据。后与客户端实现实时交流 recvfrom / sendto 5.关闭套接字 closesocket客户端程序流程: 1.加载套接字库 WSAStartup 2.创建套接字 socket 3.向服务器发送数据.后与服务端实现实时交流 recvfrom / sendto 4.关闭套接字 closesocket*/
服务器端代码:
#include <Winsock2.h> #include <stdio.h> #pragma comment(lib, "Ws2_32.lib") void main() { // 加载套接字库,并进行套接字的版本协商 WORD wVersionRequested; // 指定将要加载的 winsock 库版本 WSADATA wsaData; // 用于存储加载的 wdnsock 库版本信息 int result; // 用于检测 WSAStartup 函数运行结果 wVersionRequested = MAKEWORD(1, 1); // 设定版本 result = WSAStartup(wVersionRequested, &wsaData); // 函数 WSAStartup 调用成功返回 0 // 出错处理 if (result != 0) { return; } if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) { WSACleanup(); return; } // 创建用于套接字 SOCKET sockConnect = socket(AF_INET, SOCK_DGRAM, 0); // 绑定套接字 SOCKADDR_IN addrInfo; // 存储本地主机地址信息 addrInfo.sin_addr.S_un.S_addr = htonl(INADDR_ANY); // 本地主机地址 addrInfo.sin_port = htons(6000); // 端口号 addrInfo.sin_family = AF_INET; // 地址族 bind(sockConnect, (SOCKADDR *)&addrInfo, sizeof(SOCKADDR)); // 等待接收数据 char recvBuf[100]; // 接收数据缓冲 char sendBuf[100]; // 发送数据缓冲 char tempBuf[200]; SOCKADDR_IN addrInfoClient; // 存储客户端地址信息 int len = sizeof(SOCKADDR); while (true) { recvfrom(sockConnect, recvBuf, strlen(recvBuf), 0, (SOCKADDR *)&addrInfoClient, &len); if ('q' == recvBuf[0]) { sendto(sockConnect, "q", strlen("q") + 1, 0, (SOCKADDR *)&addrInfoClient, len); printf("聊天结束"); break; } sprintf(tempBuf, "%s 说:%s", inet_ntoa(addrInfoClient.sin_addr), recvBuf); printf("%s\n", tempBuf); // 发送数据 printf("我说:"); gets(sendBuf); sendto(sockConnect, sendBuf, strlen(sendBuf) + 1, 0, (SOCKADDR *)&addrInfoClient, len); } // 关闭套接字 closesocket(sockConnect); WSACleanup(); }
客户端代码:
#include <Winsock2.h> #include <stdio.h> #pragma comment(lib, "Ws2_32.lib") void main() { // 加载套接字库,并进行套接字的版本协商 WORD wVersionRequested; // 指定将要加载的 winsock 库版本 WSADATA wsaData; // 用于存储加载的 wdnsock 库版本信息 int result; // 用于检测 WSAStartup 函数运行结果 wVersionRequested = MAKEWORD(1, 1); // 设定版本 result = WSAStartup(wVersionRequested, &wsaData); // 函数 WSAStartup 调用成功返回 0 // 出错处理 if (result != 0) { return; } if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) { WSACleanup(); return; } // 创建套接字 SOCKET sockConnect = socket(AF_INET, SOCK_DGRAM, 0); // 向服务器发送数据 SOCKADDR_IN addrInfoServer; // 存储服务器地址信息 addrInfoServer.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); // 指定服务器地址 addrInfoServer.sin_port = htons(6000); // 端口号 addrInfoServer.sin_family = AF_INET; // 地址族 int len = sizeof(SOCKADDR); char recvBuf[100]; // 接收数据缓冲 char sendBuf[100]; // 发送数据缓冲 char tempBuf[200]; while (true) { // 发送数据 printf("我说:"); gets(sendBuf); sendto(sockConnect, sendBuf, strlen(sendBuf) + 1, 0, (SOCKADDR*)&addrInfoServer, len); // 等待并接收数据 recvfrom(sockConnect,recvBuf, strlen(recvBuf), 0, (SOCKADDR*)&addrInfoServer, &len); if ('q' == recvBuf[0]) { sendto(sockConnect, "q", strlen("q") + 1, 0, (SOCKADDR*)&addrInfoServer, len); printf("聊天结束"); break; } sprintf(tempBuf, "%s 说:%s", inet_ntoa(addrInfoServer.sin_addr), recvBuf); printf("%s\n", tempBuf); } // 关闭套接字 closesocket(sockConnect); WSACleanup(); }
3.其他
vc网络编程常用类型解析: 1. SOCKET 类型 SOCKET 是 socket 套接字类型,在 WINSOCK2.H 中有如下定义: typedef unsigned u_int; typedef u_int SOCKET; 可知套接字实际上就是一个无符号整形,它将被 Socket 环境管理和使用。 套接字将被创建、设置、用来发送和接收数据,最后会被关闭。 2.WORD 类型、MAKEWORD、LOBYTE、HIBYTE 宏 WORD 类型是一个 16 位的无符号整型, 在 WTYPES.H 中被定义为: typedef unsigned short WORD; 其目的是提供两个字节的存储, 在 Socket 中这两个字节可以表示主版本号和副版本号。 使用 MAKEWORD 宏可以给一个 WORD 类型赋值。例如要表示主版本号 2, 副版本号 0,可以使用如下代码: WORD wVersionRequested; wVersionRequested = MAKEWORD(2, 0); 注意低位内存存储主版本号 2, 高位内存存储副版本号 0,其值为 0x0002。 使用宏 LOBYTE 可以读取 WORD 的低位字节, HIBYTE 可以读取高位字节。 3.WSADATA 类型和 LPWSADATA 类型 WSADATA 类型是一个结构,描述了 Socket 库的一些相关信息,其结构定义如下: typedef struct WSAData { WORD wVersion; WORD wHighVersion; char szDescription[WSADESCRIPTION_LEN + 1]; char szSystemStatus[WSASYS_STATUS_LEN + 1]; unsigned short iMaxSockets; unsigned short iMaxUdpDg; char FAR* lpVendorInfo; }WSADATA; typedef WSADATA FAR* LPWSADATA; 值得注意的是 wVersion 字段,存储了 Socket 的版本类型。LPWSADATA 是 WSADATA 的指针类型。 他们通过 Socket 的初始化函数 WSAStartup 读取出来。 //// vc网络编程常用函数解析: 1. WSAStartup 函数 用于初始化 Socket 环境,函数原型: int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData); 其返回值为整型,调用方式为 PASCAL (即标准类型,PASCAL 等于__stdcall),参数有两个, 第一个参数为 WORD 类型,指明了 Socket 的版本号,第二个参数为 LPWSADATA,指向一个用于存储 Socket 库信息的WSAStartup结构。 返回值: 返回值为0,则初始化成功,若不为0则为失败。 2.WSACleanup 函数 这是 Socket 环境的退出函数,函数原型: int WSACleanup (void); 返回值: 返回值为0表示成功,SOCKET_ERROR 表示失败。 3.socket 函数 socket 套接字的创建函数,函数原型: SOCKET socket(int af, int type, int protocol ); 第一个参数为:int af, 代表网络地址族,目前只有一种取值有效,即 AF_INET, 代表 internet 地址族; 第二个参数为:int type, 代表网络协议类型, SOCK_DGRAM 代表 UDP 协议, SOCK_STREAM 代表 TCP 协议。 第三个参数为:int protocol,指定网络地址族特殊协议,目前无用,赋值0即可。 返回值: 返回值为 SOCKET, 若返回INVALID_SOCKET 则失败。 4.bind 函数 用于将套接字绑定到一个已知地址上,函数原型: int bind(SOCKET s, const struct sockaddr FAR *name, int namelen); 第一个参数为:SOCKET s, 指定将被绑定的套接字。 第二个参数为:SOCKADDR_IN *name, 是一个sockaddr结构指针,该结构中包含了要绑定的地址和端口。 第三个参数为:int namelen, 确定第二个参数的结构长度。 返回值: 成功返回0,失败返回SOCKET_ERROR。 /// 下面对其涉及的类型作一番解析: sockaddr 类型: sockaddr 类型是用来表示 Socket 地址的类型,同上面的 socketaddr_in 类型相比,sockaddr 的适用范围更广, 因为sockeaddr_in只适用于 TCP/IP 地址。sockaddr 的定义如下: struct sockaddr { ushort sa_family; char sa_data[14]; }; 可知sockaddr 的16个字节,而sockaddr_in也有16个字节,所以sockaddr_in是可以强制类型转换为sockadddr的。 事实上也往往使用这种方法。 sockaddr_in 定义了socket发送和接收数据包的地址,其定义如下: strucr sockaddr_in { short sin_family; u_short sin_port; struct in_addr sin_addr; char sin_zero[8]; }; 其中 in_addr 定义如下: struct in_addr { union { struct {u_char s_b1, s_b2, s_b3, s_b4} S_un_b; struct {u_short s_w1, s_w2} S_un_w; u_long S_addr; }S_un; }; 首先阐述 in_addr 的信义。 很显然它是一个存储 ip 地址的联合体,有三种表达方式: 第一种用四个字节来表示IP地址的四个数字; 第二种用两个双字节来表示IP地址; 第三种用一个长整型来表示IP地址; 给 in_addr 赋值的一种最简单方法是使用 inet_addr 函数, 它可以把一个代表IP地址的字符串赋值 转换为in_addr类型。如: addrServer.sin_addr = inet_addr("192.168.0.2"); 其反函数是 inet_ntoa,可以把一个 in_addr 类型转换为一个字符串。 sockaddr_in的含义比in_addr的含义要广泛,其各个字段的含义和取值如下: 第一字段 short sin_family,代表网络地址族,如前所述,只能取值AF_INET; 第二字段 u_short sin_port, 代表IP地址端口,由程序员指定; 第三字段 struct in_addr sin_addr, 代表IP地址; 第四个字段char sin_zero[8],是为了保证sockaddr_in与SOCKADDR类型的长度相等而填充进来的字段。 5.listen 函数 该函数让一个套接字在指定IP地址的指定端口处监听连接请求的到来,函数原型: int listen( SOCKET s, int backlog ); 该函数使得一个进程可以接受其他进程的请求,从而成为一个服务器进程。 在TCP服务器编程中listen函数把进程变为一个服务器,并指定相应的套接字变为被动连接。 listen 函数一般在调用bind之后、调用accept之前调用。 返回值: 成功则返回0,失败返回SOCKET_ERROR,可以调用函数WSAGetLastError来取得错误代码。 6.accept函数 该函数从连接请求队列中获得连接信息,并创建新的套接字用于收发数据,实现服务器与客户端的通信。函数原型: SOCKET accept(SOCKET s, struct sockaddr FAR *addr, int FAR *addrlen); 第一个参数:SOCKET s, 监听套接字 第二个参数:struct sockaddr addr, 存储请求连接的客户端IP地址、端口信息 第三个参数:int addrlen,第二个参数所占空间大小 返回值: 成功返回新套接字,失败返回错误信息 7.connect 函数 向指定的网络主机请求连接,函数原型: int connect(SOCKET s, const struct sockaddr FAR *name, int namelen); 第一个参数:SOCKET s, 客户端用于收发数据的套接字。 第二个参数:struct sockaddr *name, 指定网络主机IP地址和端口号。 第三个参数:int namelen, 第二参数长度 返回值: 成功返回0,失败返回-1。 8.sendto、recvfrom、send、recv函数 在 Socket 中有两套发送和接收函数。一是sendto 和recvfrom; 二是send 和 recv。 前一套在函数参数中要指明地址(UDP协议), 而后一套需要先将套接字和一个地址绑定,然后直接发送和接收,不需绑定地址。 函数原型: int sendto( SOCKET s, const char FAR *buf, int len, int flags, const struct sockaddr FAR *to, int tolen); int recvfrom(SOCKET s, char FAR* buf, int len, int flags, struct sockaddr FAR *from, int FAR *fromlen); int send(SOCKET s,const char FAR *buf, int len, int flags); int recv(SOCKET s, char FAR *buf, int len, int flags); 第一个参数: 套接字 第二个参数: 数据指针 第三个参数: 数据长度 第四个参数: 收发数据方式的标识,如果不需要特殊要求可以设置为0,其他值可参考MSDN; 第五个参数: 目标主机地址 第六个参数: 地址的长度 返回值: 运行成功则返回收发数据的字节数,失败返回SOCKET_ERROR 9.closesocket 函数 关闭套接字,函数原型: int closesocket( SOCKET s ); 返回值: 成功返回0,失败返回SOCKET_ERROR。
转载于:https://www.cnblogs.com/wuyuan2011woaini/p/5740975.html
MFC 网络编程 -- 总结相关推荐
- MFC 网络编程小结
最近对MFC的网络编程方面研究了一下..现在想对学习过程中的问题和一些想法做下总结. 1.现说下socket(套接字)吧,初学者刚看到这个东西的时候一定觉得很神秘,我也一样,现在也只是有一点皮毛的理解 ...
- 糖儿飞教你学C++ Socket网络编程——2.本书目录
项目1 网络编程的实现原理... 1 1.1 网络程序的类型与应用领域... 1 1.1.1 网络程序的类型... 1 1.1.2 网络程序的应用领域... 2 1.2 套接字及其种类... 4 1. ...
- MFC socket网络编程(流程示例)
MFC socket网络编程(流程示例) 1.TCP流式套接字的编程步骤 在使用之前须链接库函数:工程->设置->Link->输入ws2_32.lib,OK! 服务器端程序: 1.加 ...
- 网络编程-基于MFC的仿QQ聊天室-2020
基于MFC的仿QQ聊天室(2020) 有幸学习过网络编程的一些知识,出于对编程的热爱,把曾经的一次简单实践编程作业进行了自定义的完成. 编程所需: 编程工具为VS 2010,需要掌握MFC的基本操作以 ...
- 网络编程(三)---- MFC 仿QQ聊天软件
今天来八一八,MFC的SOCKET 编程,利用CSocket实现一个基于TCP实现一个QQ聊天程序.你会发现,MFC要比WIN32 简单的多.但是如果你不理解具体API socket基础知识,你可能会 ...
- 孙鑫MFC笔记之十二--网络编程
网络状况: ü多种通信媒介--有线.无线-- ü不同种类的设备--通用.专用-- ü不同的操作系统--Unix.Windows -- ü不同的应用环境--固定.移动-- ü不同业务种类--分时.交互. ...
- Linux C++/Java/Web/OC Socket网络编程
一,Linux C++ Socket网络编程 1.什么是TCP/IP.UDP? TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制 ...
- 完毕port(CompletionPort)具体解释 - 手把手教你玩转网络编程系列之三
手把手叫你玩转网络编程系列之三 完毕port(Completion Port)具体解释 ...
- [windows网络编程]tcp/udp编程初步详解-转
#pragma comment (lib,"ws2_32.lib") #include <Winsock2.h> #include <stdio.h> 如你 ...
最新文章
- 微信小程序外卖增长402%,茶饮下单最活跃
- MVC开发人员必备的五大工具
- .Net程序内存泄漏解析
- HDFS概述(2)————Block块大小设置
- ubuntu18的网关ip在哪里配_技术|如何在 Ubuntu 18.04 LTS 中配置 IP 地址
- 使用HTML5技术控制电脑或手机上的摄像头(转载)
- 商城管理系统源码 商城APP源码 电子商城源码
- GIS数据处理与应用开发一站式解决方案
- Git版本控制管理教程(一):介绍
- 英特尔芯片组系列 服务器,英特尔主板现在有几种架构,分别都是什么。都是对应什么系列CPU安装最好。说的越详细越好...
- 第五届阿里天池中间件比赛经历分享
- GIT 中如何打标签(git tag)
- 数据库常用操作语句总结
- 如何将刷题的效率提升10倍
- Windows、Linux系统常用CMD命令大全
- PTA字符串关键字的散列映射 (哈希表)
- Golang 函数定义 不定数目参数定义 多个输入参数函数 (...) 不定参数 可变参数 定义
- FPGA设计中,Vivado 调用IP核详细操作步骤
- UnityVR--小程序7--坦克对战
- 【陈工笔记】【复盘】# 服务器集群使用方式 #
热门文章
- Scala模式匹配:对规则进行匹配
- 在word上写博客直接发到CSDN博客
- oracle用户名无法登陆,sysdba却可以登陆
- 如何成为linux内核维护人员,Linux内核维护人员Greg Kroah-Hartman拒绝明尼苏达大学的道歉...
- paddlepaddle测试安装_PaddlePaddle升级解读 | 十余行代码完成迁移学习,PaddleHub实战篇...
- 【已解决】linux redhat 6 如何打开防火墙中的某个端口?例如:5900端口
- String类和StringBuffer类的区别
- 1.3.3 系统调用(执行过程、访管指令、库函数与系统调用)
- ISP、主机之间的通信方式、电路交换和分组交换、时延
- 南邮 Android 课程设计,南邮大四课程设计.doc