Winsock编程流程

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

用户在工程设置中,可以修改或添加库模板,在库模板中添加动态链接库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/IP
	addr.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/IP
	addr.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                         //地址结构大小
		 );



你可能感兴趣的:(Winsock编程流程)