MFC的网络编程学习摘记

Windows Socket是实现网络程序的方法之一,现对于Socket的学习经验总结如下。


1.Windows Sockets 范例定义了一套microsoft Windows 下网络编程接口。它不仅包含了人们所熟悉的Berkeley Socket 风格的库函数;也包含了一组针对Windows 的扩展库函数,以使程序员能充分地利用Windows 消息驱动机制进行编程。


2.socket通信流程.

socket是"打开—读/写—关闭"模式的实现,以使用TCP协议通讯的socket为例,其交互流程大概如下:

服务器根据地址类型(ipv4,ipv6)、socket类型、协议创建socket

服务器为socket绑定ip地址和端口号

服务器socket监听端口号请求,随时准备接收客户端发来的连接,这时候服务器的socket并没有被打开

客户端创建socket

客户端打开socket,根据服务器ip地址和端口号试图连接服务器socket

服务器socket接收到客户端socket请求,被动打开,开始接收客户端请求,直到客户端返回连接信息。这时候socket进入阻塞状态,所谓阻塞即accept()方法一直到客户端返回连接信息后才返回,开始接收下一个客户端谅解请求

客户端连接成功,向服务器发送连接状态信息

服务器accept方法返回,连接成功

客户端向socket写入信息

服务器读取信息

客户端关闭

服务器端关闭



3.WSAStartup,是Windows Sockets Asynchronous的 启动命令、Windows下的 网络编程接口软件 Winsock1 或 Winsock2 里面的一个命令。
int WSAStartup( WORD wVersionRequested, LPWSADATA lpWSAData);
⑴ wVersionRequested:一个WORD(双字节)型数值,在最高版本的Windows Sockets支持调用者使用,高阶字节指定小版本(修订本)号,低位字节指定主 版本号。
⑵lpWSAData 指向WSADATA数据结构的 指针,用来接收Windows Sockets [1]   实现的 细节。
WindowsSockets API提供的调用方可使用的最高版本号。高位 字节指出副版本(修正)号,低位字节指明主版本号。

返回值0 成功。否则返回错误代码之一。


4.WSADATA结构被用来储存调用AfxSocketInit全局函数返回的Windows Sockets初始化信息。
摘自<winsock.h>
typedef  struct  WSAData {
         WORD                     wVersion;
         WORD                     wHighVersion;
#ifdef _WIN64
         unsigned  short           iMaxSockets;
         unsigned  short           iMaxUdpDg;
         char  FAR *              lpVendorInfo;
         char                     szDescription[WSADESCRIPTION_LEN+1];
         char                     szSystemStatus[WSASYS_STATUS_LEN+1];
#else
         char                     szDescription[WSADESCRIPTION_LEN+1];
         char                     szSystemStatus[WSASYS_STATUS_LEN+1];
         unsigned  short           iMaxSockets;
         unsigned  short           iMaxUdpDg;
         char  FAR *              lpVendorInfo;
#endif
} WSADATA;
wVersion
Windows Sockets DLL期望调用者使用的Windows Sockets规范的版本。 高位 字节存储副版本号, 低位字节存储主版本号,可以用WORD MAKEWORD(BYTE,BYTE ) 返回这个值,例如:MAKEWORD(1,1)
wHighVersion
这个DLL能够支持的Windows Sockets规范的最高版本。通常它与wVersion相同。
szDescription
以null结尾的ASCII字符串,Windows Sockets DLL将对Windows Sockets实现的描述拷贝到这个字符串中,包括制造商标识。文本(最多可以有256个字符)可以包含任何字符,但是要注意不能包含 控制字符和 格式字符,应用程序对其最可能的使用方式是把它(可能被截断)显示在在状态信息中。
szSystemStatus
以null结尾的ASCII字符串,Windows Sockets DLL把有关的状态或配置信息拷贝到该字符串中。Windows Sockets DLL应当仅在这些信息对用户或支持人员有用时才使用它们,它不应被作为szDescription域的扩展。
iMaxSockets
单个进程能够打开的socket的最大数目。Windows Sockets的实现能提供一个全局的socket池,可以为任何进程分配;或者它也可以为socket分配属于进程的资源。这个数字能够很好地反映Windows Sockets DLL或网络软件的配置方式。应用程序的编写者可以通过这个数字来粗略地指明Windows Sockets的实现方式对应用程序是否有用。例如,X Windows服务器在第一次启动的时候可能会检查iMaxSockets的值:如果这个值小于8,应用程序将显示一条错误信息,指示用户重新配置网络软件(这是一种可能要使用szSystemStatus文本的场合)。显然无法保证某个应用程序能够真正分配iMaxSockets个socket,因为可能有其它WindowsSockets应用程序正在使用。
iMaxUdpDg
Windows Sockets应用程序能够发送或接收的最大的用户数据包协议(UDP)的数据包大小,以 字节为单位。如果实现方式没有限制,那么iMaxUdpDg为零。在Berkeley sockets的许多实现中,对于UDP数据包有个固有的限制(在必要时被分解),大小为8192字节。Windows Sockets的实现可以对碎片重组缓冲区的分配作出限制。对于适合的WindowsSockets 实现,iMaxUdpDg的最小值为512。注意不管iMaxUdpDg的值是什么,都不推荐你发回一个比网络的最大传送单元(MTU)还大的 广播数据包。(Windows Sockets API 没有提供发现MTU的机制,但是它不会小于512个字节)。WinSock2.0版中已被废弃。
lpVendorInfo
指向销售商的数据结构的 指针。这个结构的定义(如果有)超出了 WindowsSockets规范的范围。WinSock2.0版中已被废弃。


5.WSACleanup()的功能是 终止Winsock 2 DLL ( Ws2_32.dll) 的使用.


6.int socket(int domain, int type, int protocol);
domain:协议域,又称协议族(family)。常用的协议族有AF_INET、AF_INET6、AF_LOCAL(或称AF_UNIX,Unix域Socket)、AF_ROUTE等。协议族决定了socket的地址类型,在通信中必须采用对应的地址,如AF_INET决定了要用ipv4地址(32位的)与端口号(16位的)的组合、AF_UNIX决定了要用一个绝对路径名作为地址。
type:指定Socket类型。常用的socket类型有SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等。流式Socket(SOCK_STREAM)是一种面向连接的Socket,针对于面向连接的TCP服务应用。数据报式Socket(SOCK_DGRAM)是一种无连接的Socket,对应于无连接的 UDP服务应用。
protocol:指定协议。常用协议有IPPROTO_TCP、IPPROTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等,分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议。


7.int bind(SOCKET socket, const struct sockaddr* address, socklen_t address_len);
socket:是一个 套接字描述符。
address:是一个sockaddr结构 指针,该结构中包含了要结合的地址和 端口号。
address_len:确定address 缓冲区的长度。
返回值:
如果函数执行成功,返回值为0,否则为SOCKET_ERROR。


8. sockaddr结构
struct sockaddr
{
unsigned short sa_family;/*addressfamily,AF_xxx*/
char sa_data[14];/*14bytesofprotocoladdress*/
};
sa_family是地址家族,一般都是“AF_xxx”的形式。通常大多用的是都是 AF_INET,代表TCP/IP协议族。
sa_data是14字节 协议地址。
此数据结构用做bind、connect、recvfrom、sendto等函数的参数,指明地址信息。但一般编程中并不直接针对此数据结构操作,而是使用另一个与sockaddr等价的数据结构


9. sockaddr_in(在netinet/in.h中定义):

struct  sockaddr_in
 
{
 
short  sin_family; /*Address family一般来说AF_INET(地址族)PF_INET(协议族)*/
 
unsigned  short  sin_port; /*Port number(必须要采用网络数据格式,普通数字可以用htons()函数转换成网络数据格式的数字)*/
 
struct  in_addr sin_addr; /*IP address in network byte order(Internet address)*/
 
unsigned  char  sin_zero[8]; /*Same size as struct sockaddr没有实际意义,只是为了 跟SOCKADDR结构在内存中对齐*/
 
};

sin_family指代协议族,在socket编程中只能是AF_INET
sin_port存储 端口号(使用网络 字节顺序),在linux下,端口号的范围0~65535,同时0~1024范围的端口号已经被系统使用或保留。
s in_addr存储IP地址,使用in_addr这个数据结构
sin_zero是为了让sockaddr与sockaddr_in两个数据结构保持大小相同而保留的空字节。
s_addr按照网络字节顺序存储IP地址
sockaddr_in和sockaddr是并列的结构,指向sockaddr_in的 结构体的 指针也可以指向
sockaddr的结构体,并代替它。也就是说,你可以使用sockaddr_in建立你所需要的信息,
然后用memset函数初始化就可以了memset((char*)&mysock,0,sizeof(mysock));//初始化


10.in_addr_t inet_addr(const char* strptr);
返回:若字符串有效则将字符串转换为32位二进制网络 字节序的IPV4地址,否则为INADDR_NONE

char *inet_ntoa( struct  in_addr in);
将一个IP转换成一个互联网标准点分格式的字符串。


11.listen()创建一个套接口并监听申请的连接.
int PASCAL FAR listen( SOCKET s, int backlog);
S:用于标识一个已捆绑未连接套接口的描述字。
backlog:等待连接队列的最大长度。


12.accept()在一个套接口接受一个连接。
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
sockfd:套接字描述符,该套接口在 listen()后监听连接。
addr:(可选)指针,指向一缓冲区,其中接收为通讯层所知的连接实体的地址。Addr参数的实际格式由套接口创建时所产生的地址族确定。
addrlen:(可选)指针,输入参数,配合addr一起使用,指向存有addr地址长度的整型数。

返回值:如果没有错误产生,则accept()返回一个描述所接受包的SOCKET类型的值。否则的话,返回INVALID_SOCKET错误,应用程序可通过调用WSAGetLastError()来获得特定的错误代码。

13.send()用于向一个已经连接的socket发送数据,如果无错误,返回值为所发送数据的总数,否则返回SOCKET_ERROR。
#include < winsock.h>
int PASCAL FAR send( SOCKET s, const char FAR* buf, int len, int flags);
s:一个用于标识已连接套接口的描述字。
buf:包含待发送数据的 缓冲区。
len:缓冲区中数据的长度。
flags:调用执行方式。


14.recv()是编程语言函数。本函数用于已连接的数据报或流式 套接口进行数据的接收。
函数原型int recv( _In_ SOCKET s, _Out_ char *buf, _In_ int len, _In_ int flags);

第一个参数指定接收端套接字描述符;

第二个参数指明一个缓冲区,该缓冲区用来存放recv函数接收到的数据;

第三个参数指明buf的长度;

第四个参数一般置0



15.connect()用来将参数sockfd 的socket 连至参数serv_addr 指定的网络地址。参数addrlen为sockaddr的结构长度。

int connect (int sockfd,struct sockaddr * serv_addr,int addrlen);
参数一: 套接字描述符
参数二:指向数据结构sockaddr的 指针,其中包括目的端口和IP地址
参数三:参数二sockaddr的长度,可以通过sizeof(struct sockaddr)获得

成功则返回0,失败返回非0, 错误码GetLastError()。


16.: recvfrom()用来接收远程主机经指定的socket传来的数据,并把数据传到由参数buf指向的内存空间,参数len为可接收数据的最大长度.参数flags一般设0,其他数值定义参考recv().参数from用来指定欲传送的 网络地址,结构sockaddr请参考bind()函数.参数fromlen为sockaddr的结构长度.

函数原型:ssize_t recvfrom(int sockfd,void *buf,int len,unsigned int flags, struct sockaddr *from,socket_t *fromlen); ssize_t 相当于 int,socket_t 相当于int ,这里用这个名字为的是提高代码的自说明性。


17.sendto() 用来将数据由指定的socket传给对方主机。参数s为已建好连线的socket,如果利用UDP协议则不需经过连线操作。参数msg指向欲连线的数据内容,参数flags 一般设0,详细描述请参考send()。参数to用来指定欲传送的网络地址,结构sockaddr请参考bind()。参数tolen为sockaddr的结构长度。成功则返回实际传送出去的字符数,失败返回-1,错误原因存于errno 中。

int PASCAL FAR sendto (
IN SOCKET s,
IN const char FAR * buf,
IN int len,
IN int flags,
IN const struct sockaddr FAR *to,
IN int tolen);
s 套接字
buff 待发送数据的缓冲区
size 缓冲区长度
Flags 调用方式标志位, 一般为0, 改变Flags,将会改变Sendto发送的形式
addr (可选) 指针,指向目的套接字的地址
len addr所指地址的长度

18.htons的功能:将一个无符号短整型的主机数值转换为网络 字节顺序,即大尾顺序(big-endian)
#include <winsock.h>
u_short PASCAL FAR htons( u_short hostshort);
hostshort:主机字节顺序表达的16位数。

htonl()将主机数转换成无符号长整形的网络 字节顺序。
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong);
hostlong:主机字节顺序表达的32位数。


19.MAKEWORD 宏 平台:SDK这个宏创建一个无符号16位整形,通过连接两个给定的无符号参数。
WORD MAKEWORD(
BYTE bLow, //指定新变量的低 字节序;
BYTE bHigh //指定新变量的高字节序;
);


20.
LOBYTE()得到一个16bit数最低(最右边)那个字节
HIBYTE()得到一个16bit数最高(最左边)那个字节


21.INADDR_ANY就是指定地址为0.0.0.0的地址,这个地址事实上表示不确定地址,或“所有地址”、“任意地址”。 一般来说,在各个系统中均定义成为0值。


22. 网络编程时可用端口号的范围是1~65535,最好是10000以后,这样不会和系统协议所使用的端口重合。


23.sprintf()函数. 字符串格式化命令,主要功能是把格式化的数据写入某个字符串中。sprintf 是个 变参函数。
int sprintf( char *buffer, const char *format, [ argument] … );
buffer: char型指针,指向将要写入的字符串的缓冲区。
format:格式化字符串。
[argument].. .:可选参数,可以是任何类型的数据。
返回值:字符串长度( strlen)


24.gets()函数用来从标准输入设备(键盘)读取 字符串直到换行符结束,但换行符会被丢弃,然后在末尾添加'\0'字符。其调用格式为:
gets(s);
其中s为字符串变量(字符串 数组名或字符串 指针)。
gets(s)函数与 scanf("%s",s)相似,但不完全相同,使用scanf("%s",s) 函数输入字符串时存在一个问题,就是如果输入了空格会认为字符串结束,空格后的字符将作为下一个输入项处理,但gets()函数将接收输入的整个字符串直到遇到换行为止。
也就是说:gets()函数读取到\n(我们输入的回车)于是停止读取,但是它不会把\n包含到字符串里面去。然而,和它配合使用的puts函数,却在输出字符串的时候自动换行。


25.127.0.0.1是 回送地址,指本地机,一般用来测试使用。回送地址(127.x.x.x)是本机回送地址(Loopback Address),即 主机IP 堆栈内部的IP地址,主要用于网络软件测试以及本地机 进程间通信,无论什么程序,一旦使用回送地址发送数据,协议软件立即返回,不进行任何网络传输。






你可能感兴趣的:(MFC的网络编程学习摘记)