Winsock编程流程

来源:互联网 发布:ip core网络什么意思 编辑:程序博客网 时间:2024/05/24 23:12

一、初始化和释放套接字库

用户在工程设置中,可以修改或添加库模板,在库模板中添加动态链接库WS2_32.dll,这样在程序中能调用winsock函数。

注:用户必须首先从动态链接库中调用函数WSAstartup()对该库进行初始化,之后才能从该库中继续正确调用其他Winsock函数,否则,就会出现错误。

int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSADate);

参数lpWSAData指向结构体WSADATA的指针变量,表示获取到的套接字库详细信息。结构体如下:

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, FAR * LPWSADATA;

用户初始套接字库如下:

WSAData data;                              //定义WSAData变量WORD wVersionRequested = MAKEWORD(2, 0);   //定义套接字库的版本号::WSAStartup(wVersionRequested, &data);    //初始化套接字库

当程序退出时,用户还应该调用函数WSACleanup()释放该套接字库

::WSACleanup();


二、创建套接字句柄

在Socket API中,创建套接字句柄的函数是socket(),函数原型如下:

SOCKET socket {int af;        //指定套接字所使用的地址格式int type;      //套接字类型int protocol;   //如果参数type已经指定套接字类型为TCP或UDP,则该参数可以设置为0};
该函数执行成功,将返回新创建的套接字句柄,否则将返回INVALID_SOCKET表示失败。

例如,创建流式套接字的句柄。

SOCKET s;s = ::socket(AF_INET, SOCK_STREAM, 0);

三、绑定地址信息

对于服务器而言,套接字创建成功后,还应该将套接字与地址结构信息相关联。函数Bind()。

int bind( SOCKET s,                           //套接字句柄    const struct sockaddr FAR* name,    //地址结构信息int namelen                         //地址结构大小 );

该函数调用成功,则返回0.

例如将套接字句柄绑定到本地地址,代码如下:

sockaddr_in addr;                      //定义套接字地址结构变量in_addr     in_add;                    //定义IP地址结构变量addr.sin_family = AF_INET;             //指定地址家族为TCP/IPaddr.sin_port = htons(80);             //指定端口号addr.sin_addr.S_un.S_addr = INADDR_ANY;//表示服务器能接收任何计算机发过来的请求::bind(s, (sockaddr)&addr, sizeof(addr));//绑定套接字到指定地址结构
当服务器程序将套接字句柄绑定套接字地址成功时,则调用函数Listen()实现监听端口的功能。

int listen(SOCKET s,        //实现监听功能的套接字句柄int backlog      //指定监听的最大连接数量);
该函数仅用于流式套接字。如果多个客户端同时向服务器发出连接请求,并以及超过了最大监听数,则客户端将返回错误代码。


四、连接

客户端程序连接服务器使用函数connect()实现

int connect(SOCKET s,                        //套接字句柄const struct sockaddr FAR* name, //将要连接的服务器地址信息结构指针int namelen                      //地址信息结构体长度)
例如,客户端使用该函数连接地址为“127.0.0.1”,端口为80的服务器。

sockaddr_in addr;in_addr in_add;addr.sin_family = AF_INET;addr.sin_port = htons(80);addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");   //指定服务器地址SOCKET s;                                             //定义套接字句柄s = ::socket(AF_INET, SOCK_STREAM, 0);                //创建并返回套接字句柄::connect(s, (sockaddr)&addr, sizeof(addr));         //连接服务器

如果服务器接收到客户端的连接请求,则可以调用函数accept()接受该请求。


SOCKET accept(SOCKET s,struct sockaddr FAR* addr,              //获取连接对方的地址信息int FAR* addrlen                        //地址长度);

该函数如果调用成功,则返回一个新的套接字句柄,用于通信双方数据的传输


五、数据收发

当用户使用Winsock编程时,都是调用函数send和recv进行数据的发送和接收。

int send(SOCKET s, const char FAR* buf, int len, int flags);int recv(SOCKET s,  char FAR* buf, int len, int flags);

注:如果服务器使用上面的函数进行数据收发,则参数s应该为监听函数返回的新套接字句柄。

      如果客户端使用以上函数进行数据收发,则参数s应该为客户端创建的套接字句柄。

六、关闭套接字

closesocket()关闭套接字句柄


--------------------------------------------------------------------------------------

// Socket.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"struct sockaddr_in{short               sin_family;            //指定地址家族即地址格式unsigned short      sin_port;              //端口号码struct in_addr      sin_addr;              //IP地址char                sin_zero[8];           //留作备用,需要指定为0};struct in_addr {union {struct {unsigned char s_b1, s_b2, s_b3, s_b4;}S_un_b;                                  //用4个u_char字符描述IP地址struct  {unsigned short s_w1, s_w2;           //用2个u_short类型描述IP地址}S_un_w;unsigned long S_addr;                    //用1个u_long类型描述IP地址}S_un;};int _tmain(int argc, _TCHAR* argv[]){sockaddr_in addr;                      //定义套接字地址结构变量in_addr     in_add;                    //定义IP地址结构变量addr.sin_family = AF_INET;             //指定地址家族为TCP/IPaddr.sin_port = htons(80);             //指定端口号addr.sin_addr.S_un.S_addr = INADDR_ANY;//表示服务器能接收任何计算机发过来的请求::bind(s, (sockaddr)&addr, sizeof(addr));//绑定套接字到指定地址结构int listen(SOCKET s,        //实现监听功能的套接字句柄int backlog      //指定监听的最大连接数量);int connect(SOCKET s,                        //套接字句柄const struct sockaddr FAR* name, //将要连接的服务器地址信息结构指针int namelen                      //地址信息结构体长度)sockaddr_in addr;in_addr in_add;addr.sin_family = AF_INET;addr.sin_port = htons(80);addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");   //指定服务器地址SOCKET s;                                             //定义套接字句柄s = ::socket(AF_INET, SOCK_STREAM, 0);                //创建并返回套接字句柄::connect(s, (sockaddr)&addr, sizeof(addr));         //连接服务器SOCKET accept(SOCKET s,struct sockaddr FAR* addr,              //获取连接对方的地址信息int FAR* addrlen                        //地址长度);int send(SOCKET s, const char FAR* buf, int len, int flags);int recv(SOCKET s,  char FAR* buf, int len, int flags);return 0;}int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSADate);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, FAR * LPWSADATA;WSAData data;                              //定义WSAData变量WORD wVersionRequested = MAKEWORD(2, 0);   //定义套接字库的版本号::WSAStartup(wVersionRequested, &data);    //初始化套接字库SOCKET socket {int af;        //指定套接字所使用的地址格式int type;      //套接字类型int protocol;   //如果参数type已经指定套接字类型为TCP或UDP,则该参数可以设置为0};SOCKET s;s = ::socket(AF_INET, SOCK_STREAM, 0);int bind( SOCKET s,                           //套接字句柄    const struct sockaddr FAR* name,    //地址结构信息int namelen                         //地址结构大小 );



0 0