Windows下的Winsock编程有阻塞、非阻塞以及各种I/O模型。阻塞模型是最基本也是最简单的方式。Winsock有两个版本,Winsock 1和Winsock 2,两者都可以在(除wince之外的)的所有windows操作系统上运行。Wince只支持Windsock 1。当使用WINSOCK2.H时需要连接WS2_32.lib库,使用WINSOCH.H时用WSOCK32.LIB库。接下来分别介绍阻塞模式服务器端和客户端。
在实际应用中,服务器几乎都不用阻塞模式实现,但是作为学习来说,还是一步步来,从理解阻塞模式。阻塞模式简单服务器端实现步骤如下:
1、 初始化
2、 创建socket套接字
3、 绑定套接字
4、 监听
5、 接受连接
6、 接收数据
#include "stdafx.h"
#include <windows.h>
#include <process.h>
#include <WINSOCK2.H>
#pragma comment(lib,"WS2_32.lib")
DWORD WINAPI RecData(LPVOID lparam)
{
SOCKET *psocket=(SOCKET *)lparam;
if(psocket!=NULL)
{
char rec[1024]={0};
int i=0;
//接收数据
i=recv(*psocket,rec,1024,0);
printf("%s\n",rec);
closesocket(*psocket);
}
return 0;
}
int main(int argc, char* argv[])
{
WSADATA wsa;
SOCKET ServSoc;
SOCKET Newconnection;
sockaddr_in SerAddr;
sockaddr_in ClientAddr;
//初始化socket版本2.2
if(0!=WSAStartup(MAKEWORD(2,2),&wsa))
return 0;
//判定版本是不是2.2,不是的话说明版本不符合要求
if(LOBYTE(wsa.wVersion)!=2||HIBYTE(wsa.wVersion)!=2)
{
//不符合要求就要释放资源,一旦WSAStartup,最后都必需要用WSACleanup
WSACleanup();
printf("%s","version is not fit\n");
return 0;
}
//创建一个套接字,用来监听客户连接
ServSoc=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(INVALID_SOCKET==ServSoc)
{
WSACleanup();
printf("%s","Socket init failed\n");
return 0;
}
//建立一个sockaddr_in,监听端口设置为5150,地址用INADDR_ANY,当服务器有n个ip时,将指向任意空闲ip。
//在设置过程中都要将主机字节顺序转换为网络字节顺序,即htons、htonl
SerAddr.sin_family=AF_INET;
SerAddr.sin_port=htons(5150);
SerAddr.sin_addr.s_addr=htonl(INADDR_ANY);
//将监听端口和服务器地址和套接字关联起来,即绑定
if(SOCKET_ERROR==bind(ServSoc,(sockaddr *)&SerAddr,sizeof(SerAddr)))
{
closesocket(ServSoc);
WSACleanup();
printf("%s","the binding operation failed\n");
return 0;
}
int ilen=sizeof(sockaddr_in);
while(1)
{
//监听客户机连接,连接数最大为5
if(SOCKET_ERROR!=listen(ServSoc,5))
{
//接受连接,返回一个新的套接字,之后与这个连接的操作都是通过这个套接字来实现的。
//当再次对ServSoc调用accept时,又可以接受新的连接
Newconnection=accept(ServSoc,(sockaddr *)&ClientAddr,&ilen);
if(INVALID_SOCKET!=Newconnection)
{
//对刚刚的连接开启一个线程接受数据,传入的参数是新建的那个套接字
HANDLE m_hThread=(HANDLE)_beginthreadex(NULL,0,(unsigned int( __stdcall *)(void *))RecData,&Newconnection,CREATE_SUSPENDED,NULL);
if(NULL!=m_hThread)
{
ResumeThread(m_hThread);
CloseHandle(m_hThread);
}
printf("Hello World!\n");
}
}
Sleep(0);
}
//最后关闭套接字,WSACleanup释放相关资源
closesocket(ServSoc);
WSACleanup();
return 0;
}
客户端简单实现步骤如下:
1、 初始化
2、 创建socket套接字
3、 连接服务器
4、 发送数据
#include "stdafx.h"
#include <WINSOCK2.H>
#include <iostream>
#pragma comment(lib,"WS2_32.lib")
int main(int argc, char* argv[])
{
WSADATA wsa;
SOCKET ClientSoc;
sockaddr_in SerAddr;
//初始化socket版本2.2
if(0!=WSAStartup(MAKEWORD(2,2),&wsa))
{
printf("%s","WSAStartup operation failed\n");
return 0;
}
//创建一个套接字
ClientSoc=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(INVALID_SOCKET==ClientSoc)
{
WSACleanup();
printf("%s","socket init failed\n");
return 0;
}
//建立一个sockaddr_in,服务器监听端口为5150,服务器ip地址192.168.1.116
//在设置过程中htons将主机字节顺序转换为网络字节顺序,inet_addr将一个点分十进制的IP转换成一个长整数型数
SerAddr.sin_family=AF_INET;
SerAddr.sin_port=htons(5150);
SerAddr.sin_addr.s_addr=inet_addr("192.168.1.116");
//连接服务器
if(SOCKET_ERROR==connect(ClientSoc,(sockaddr *)&SerAddr,sizeof(sockaddr_in)))
{
printf("%s","the connect operation failed\n");
closesocket(ClientSoc);
WSACleanup();
return 0;
}
char buf[1024]={0};
strcpy(buf,"connet server success");
int i=0;
//发送数据
i=send(ClientSoc,buf,strlen(buf),0);
printf("Hello World!\n");
//最后关闭套接字,WSACleanup释放相关资源
closesocket(ClientSoc);
WSACleanup();
std::cin>>i;
return 0;
}
结果如下: