使用winsock进行网络开发首先需要了解下和winsock相关的函数及相关的参数
每一个使用winsock进行网络开发的windows应用程序都必须包含Winsock.h(这是一个第二版本的winsock库)这个头文件。还需要包含一个静态库ws_32.lib。使用他们的时候需要对这个库进行一次初始化,使用完毕后要对该库进行释放。使用如下函数初始化ws2_32.dll动态链接库
int WSAStartup(
WORD wVersiuonRequested,
LPWSADATA lpWSAData
);
这个动态连接库是所有网络应用程序会加载的动态链接库,如果不初始化,相关的函数调用会失败。
参数说明:
1) wVersionRequested:Windows Sockets API提供的调用方科使用的最高版本号。高位字节指出副版本(修正)号,低位字节指出主版本号。
2) IpWSAData:指向WSADATA数据结构指针,用来接收windows Sockets实现的细节。
释放ws_32.dll动态链接库
int WSACleanup(void);
这个函数是结束这个动态链接库的,一般在函数结束时使用
创建套接字:
SOCKET socket(
int af,
int type,
int protocol
);
参数说明:
1) Af:指定应用程序使用的通信协议族,对于TCP/IP协议族,该协议始终为PF_INET(或AF_INET)。
2) Type:指定要创建的套接字的类型,流套接字类型为SOCK_STREAM,数据包套接字为SOCK_DGRAM。前者通常是TCP协议使用,后者通常是UDP协议使用。
3) Protocal:指定应用程序所使用的通信协议。该参数根据第二个参数而定:IPPROTO_TCP 或IPPROTO_UDP。
该函数的返回值是一个新创建的类型为socket的套接字的描述符。
关闭套接字:
Int closesocket(
SOCKET s
);
程序结束时要对Socket创建的套接字进行关闭,完成资源的释放。
参数说明如下:
s: socket()函数创建的套接字描述符。
当创建一个Socket后,服务器必须要绑定一个IP地址和特定的端口号。客户端程序不需要绑定端口号和IP地址,因为Socket会选择合适的IP地址及端口来使用。
绑定IP地址和端口号:
int bind(
SOCKET s,
const struct sockaddr FAR *name,
int namelen
);
参数说明如下:
1) S:指定待绑定的Socket描述符。
2) name:指定一个sockaddr结构,该结构的定义如下:
struct sockaddr(
u_short as_family;
char sa_data[14];
);
函数中提供的参数类型是sockaddr,在实际使用过程中,结构体是sockaddr_in,结构体的定义如下:
struct sockaddr_in{
short sin_family;
u_short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
成员变量sin_family设置成PF_INET;sin_port设置为端口号;sin_addr结构体中只包含一个共用体,in_addr的定义如下:
Struct in_addr{
union{
struct { u_char s_b1,sb2,sb3,sb4; } S_un_b;
struct{ u_short s_w1,s_w2; } S_un_w;
u_longS_addr;
}S_un;
};
该成员变量是一个整数,一般用函数inet_addr()把字符串形式的ip地址转换成unsigned long整型的整数值。
namelen: 指定name缓冲区的长度。
Inet_addr:函数的原型如下。
unsngned long inet_addr(
const char FAR *cp
);
参数cp为一个点分多进制的IP地址。
inet_addr 函数的逆函数如下:
char FAR * inet_ntoa(
struct in_addr in
);
参数为一个addr_in类型的变量。
监听端口:
int listen(
SOCKET s,
int backlog
);
参数说明如下:
1) s:使流套接字s处于监听状态。
2) backlog:为处于监听状态的流套接字s维护一个客户连接请求队列。
接受请求:
SOCKET accept(
SOCKET s;
struct sockaddr FAR *addr,
int FAR *addrlen
);
服务端程序调用该函数从监听状态的流套接字的客户端请求队列中取出第一个请求,并创建一个新的套接字与客户端进行通信。
参数说明:
1) s:指定处于监听状态的套接字。
2) addr:用于返回新创建的套接字的地址。
3) addrlen:用来返回新创建套接字的地址结构的长度。
连接函数如下:
int connect(
SOCKET s,
const struct sockaddr FAR *name,
int namelen
);
客户端程序调用该函数来完成与远程服务器端的链接。
参数说明如下:
1) s:客户端创建的套接字。
2) name:该结构中包含了要服务器端中的IP地址和端口号。
3) namelen:指定name缓冲区的长度。
具体用于通讯的函数分为两类,一类是基于TCP协议的,另一类是基于UDP协议的。数据的通信主要体现在数据的收发上,分别看一下这两种协议的收发数据的函数定义。
基于TCP的发送函数:
int send(
SCOKET s,
const char FAR *buf,
int len,
int flags
);
参数说明如下:
1) s:指定发送端套接字描述符。
2) buf:指明一个存放应用程序要发送数据的缓冲区。
3) len:指明实际要发送到数据的字节数。
4) flags:一般设置为0。
基于TCP的接收函数:
int recv(
SOCKET s,
char FAR *buf,
int len,
int flags
);
参数说明如下:
1) s:指定接收端套接字描述符。
2) buf:指定一个缓冲区,用来存放接收到的数据。
3) len:指定缓冲区的长度。
4) flags:一般设置为0。
基于UDP的发送函数:
int sendto(
SOCKET s,
const char FAR *buf,
int len,
int flags,
const struct sockaddr FAR *to,
int tolen
);
基于UDP的接收函数:
int recvform(
SOCKET s,
char FAR* buf,
int len,
int flags,
struct sockaddr FAR *from,
int FAR *fromlen
);
1. 基于TCP协议的简单程序编写
(1) 服务器端的代码编写流程如下:
WSAStartup()->socket()->bind()->listen()->accept()->send()/recv()->closesocket()->WSACleanup().
初始化->新建套接字->绑定本地IP和端口->接受请求->发送/接收数据->关闭套接字->释放动态链接库。
(2) 客户端的代码编写流程如下:
WSAStartup()->socket()->connect ()->recv()/send()->closesocket()->WSACleanup().
初始化->新建套接字->连接服务器->接收/发送数据->关闭套接字->释放动态链接库。
2. 基于TCP协议的简单程序编写
(1) 服务器端的代码编写流程如下:
WSAStartup()->socket()->bind()->recvfrom()->sendto()->closesocket()->WSACleanup().
初始化->新建套接字->绑定本地IP和端口->接受函数->发送函数->关闭套接字->释放动态链接库。
(2) 客户端的代码编写流程如下:
WSAStartup()->socket()->bind()->sendto()->recvfrom()->closesocket()->WSACleanup().
初始化->新建套接字->绑定本地IP和端口->发送函数->接受函数->关闭套接字->释放动态链接库。