准备工作:
1 导入头文件winsock2.h
2 链接ws2_32.lib库
3 调用WSAStartup(WORD wVersionRequested,LPWSADATA lpwsaData);
说明:
1 成功时返回0,失败时返回非零的错误代码值
2 wVersionRequested:程序员要使用的Winsock版本信息。高八位为副版本号,低八位为主版本号
常用MAKEWORD宏来函数构建:MAKEWORD(1,2):主版本为1,副版本为2,返回0x0201。
3 lpwsaData:WSADATA结构体变量的地址值
作用是在相应参数中填充已经初始化的库信息。
初始化公式:
int main(int argc,char* argv[])//argc是命令行总的参数个数 ,argv[]里记录了用户输入的参数,其中第0个参数是程序的全名
{
WSADATA wsaData;
……
if(WSAStartup(MAKEWORD(2,2),&wsaData)! = 0
ErrorHandling("WSAStartup() error!");
……
return 0;
}
#include
SOCKET socket(int af,int type,int protocol);
说明:
1 成功时返回套接字句柄,失败时返回INVALID_SOCKET
2 int af:协议族信息,对于TCP/IP协议的套接字,它只能是AF_INET(也可以写成PF_INET)
3 int type:套接字类型,SOCK_STREAM/SOCK_DGRAM
4 int protocol:最终决定的协议,一般情况下为0,即系统选择
服务器:
int bind(SOCKET s,const struct sockaddr *name,int namelen);
说明:
1 成功时返回0,失败时返回SOCKET_ERROR.
2 SOCKET s:由socket函数返回的套接字句柄
3 const struct sockaddr * name:sockaddr_in 结构指针,指向赋给套接字的本地地址
sockaddr_in.family:协议族
sockaddr_in.sin_addr.S_addr:地址,若为htonl(INADDR_ANY),则表示程序不关心分配的地址
sockaddr_in.sin_port :端口,若为 htons(nServPort),则随意分配一个1024——5000之间的端口
4 int namelen: sockaddr结构的长度
用法演示:
SOCKET s;
struct sockaddr_in servAddr;
int nServPort = 5500;
int nErrCode;
servAddr.family = AF_INET;
servAddr.sin_addr.S_addr = htonl(INADDR_ANY);
servAddr.sin_port = htons(nServPort);
nErrCode = bind(s,(sockaddr *)&servAddr,sizeof(servAddr));
if(SOCKET_ERROR == nErrCode)
{
//绑定套接字失败
}
int listen(SOCKET s,int backlog);
说明:
1 成功时返回0,失败时返回SOCKET_ERROR
2 SOCKET s:由socket函数返回IDE套接字句柄
3 int backlog:知道等待连接的最大队列长度
SOCKET accept(SOCKET s,struct sockaddr *addr,int * addrlen);
说明:
1 成功则返回一个新的套接字句柄,失败则返回INVALID_SOCKET
2 SOCKET s:监听套接字
3 struct sockaddr *addr :返回客户端的地址信息
4 int * addrlen:返回sockaddr结构体长度
用法演示:
SOCKET sListen;
SOCKET sAccept;
sockaddr_in addrClient;
int addrClientlen = sizeof(addrClient);
sAccept = accept(sListen,(sockaddr *)&addrClient,&addrClientlen);
if(INVALID_SOCKET == sAccept)
{
//失败处理
}
int closesocket(SOCKET s);
说明:
1 关闭套接字,成功时返回0,失败时返回SOCKET_ERROR
int recv(SOCKET s,char FAR* buf,int len,int flags);
说明:
1 用于接受数据,成功时返回接受的字节数,失败时返回SOCKET_ERROR。
2 SOCKET s:接受套接字
3 char FAR* buf:接受数据缓冲区
4 int len:缓冲区长度
5 int flags:该参数影响该函数的行为。
取值为0:表示无特殊行为
取值为MSG_PEEK:使有用的数据被复制到接受缓冲区内,但没有从系统缓冲区删除
取值为MSG_OOB: 表示处理带外数据
用法演示:
SOCKET s;
char buf[128];
int nReadLen;
nReadLen = recv(s,buf[128],128,0);
if(SOCKET_ERROR == nReadLen)
{
//失败处理
}
客户端:
int connect(SOCKET s,const struct sockaddr *name,int namelen);
说明:
1 成功时返回0,失败时返回SOCKET_ERROR
2 SOCKET s:由socket函数返回的套接字句柄
3 const struct sockaddr *name:服务器地址
4 int namelen:sockaddr结构体长度
注:
htonl:host to net long int 将主机的无符号长整型数转换为网络字节顺序
htons: host to net short int 将主机的无符号短整型数转换为网络字节顺序
实例演示:
该实例通过客户端向服务器发送“MyTCP”字符串,服务器接收该字符串并显示出来。
客户端发送后退出,服务器显示后退出。
//Server:
WSADATA wsd;
SOCKET sServer;
int retVal;
//初始化套接字动态库
if(WSAStartup(MAKEWORD(2,2),&wsd) != 0)
{
printf("WSAStartup failed!\n");
return 1;
}
//创建套接字
sServer = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(INVALID_SOCKET == sServer)
{
printf("socket failed!");
WSACleanup(); //释放套接字资源
return -1;
}
//绑定套接字
SOCKADDR_IN addrServ; //服务器地址
addrServ.sin_family = AF_INET;
addrServ.sin_port = htons(4999);
addrServ.sin_addr.s_addr = INADDR_ANY;
retVal = bind(sServer,(SOCKADDR *)&addrServ,sizeof(SOCKADDR_IN));
if(SOCKET_ERROR == retVal)
{
printf("bind failed!\n");
closesocket(sServer); //关闭套接字
WSACleanup();
return -1;
}
//监听
retVal = listen(sServer,1);
if(SOCKET_ERROR == retVal)
{
printf("listen failed!\n");
closesocket(sServer);
WSACleanup();
return -1:
}
//等待客户端连接
SOCKET sClient;
sockaddr_in addrClient;
int addrClientlen = sizeof(addrClient);
sClient = accept(sServer,(sockaddr *)&addrClient,&addrClientlen);
if(INVALID_SOCKET == sClient)
{
printf("accept failed!\n");
closesocket(sServer);
WSACleanup();
return -1;
}
//接受并显示数据
#define BUF_SIZE 64
ZeroMemory(buf,BUF_SIZE); //将接受缓冲区清0
retVal = recv(sClient,buf,BUF_SIZE,0);
if(SOCKET_ERROR == retVal)
{
printf("recv failed!\n");
closesocket(sServer);
WSACleanup();
return -1;
}
printf("%s \n",buf);
//退出
closesocket(sServer);
closesocket(sClient);
WSACleanup();
//Client:
#define BUF_SIZE 64
WSADATA wsd;
SOCKET sHost; //服务器套接字
SOCKADDR_IN servAddr; //服务器地址
char buf[BUF_SIZE];
int retVal;
//初始化套接字动态库
if(WSAStartup(MAKEWORD(2,2),&wsd) != 0)
{
printf("WSAStartup failed!\n");
return -1;
}
//创建套接字
sHost = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(INADDR_SOCKET == sHost)
{
printf("socket failed!\n");
WSACleanup();
return -1;
}
//连接服务器
sevrAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
servAddr.sin_port = htons((short)4999);
int nServAddlen = sizeof(servAddr);
retVal = connect(sHost,(LPSOCKADDR)&servAddr,nServAddlen);
if(SOCKET_ERROR == retVal)
{
printf("connect failed!\n");
closesocket(sHost);
WSACleanup();
return -1;
}
//发送数据
ZeroMemory(buf,BUF_SIZE);
stpcpy(buf,"MyTcp");
retVal = send(sHost,buf,strlen(buf),0);
if(SOCKET_ERROR == retVal)
{
printf("send failed! \n");
closesocket(sHost);
WSACleanup();
return -1;
}
//退出
closesocket(sHost);
WSACleanup();
参考《精通Windows Sockets 网络开发 ——基于Visual C++ 实现》 --孙海民