MFC Windows Sockets服务器创建

1.初始化与绑定服务器

WSADATA wsadata;
if (WSAStartup(MAKEWORD(2, 1), &wsaData)) //调用Windows Sockets DLL
{
	error = _T("winSock 初始化失败");
	WSACleanup();
	return FALSE;
}

头文件 header:  Winsock2.h

库library: Ws2_32.lib
原型:int PASCAL FAR WSAStartup ( WORD wVersionRequested, LPWSADATA lpWSAData );
参数:(1).wVersionRequested是Windows Sockets API提供的调用方可使用的最高版本号。高位字节指出副版本(修正)号,低位字节指明主版本号。
(2).lpWSAData 是指向WSADATA数据结构的指针,用来接收Windows Sockets实现的细节。

2.开始创建服务器socket

ServerSocket = socket(PF_INET,SOCK_STREAM,0);
if (ServerSocket == INVALID_SOCKET)
{
	error = _T("无法创建服务器socket!");
	return FALSE;
}

int socket( int af, int type, int protocol);
af:一个地址描述。仅支持AF_INET格式,也就是说ARPA Internet地址格式。
type:指定socket类型。新套接口的类型描述类型,如TCP(SOCK_STREAM)和UDP(SOCK_DGRAM)。常用的socket类型有,SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等等。
protocol:顾名思义,就是指定协议。套接口所用的协议。如调用者不想指定,可用0。常用的协议有,IPPROTO_TCP、IPPROTO_UDP、IPPROTO_STCP、IPPROTO_TIPC等,它们分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议。

3.IP与Port设定

m_sockServerAddr.sin_family = AF_INET;
m_sockServerAddr.sin_addr.s_addr = INADDR_ANY;   //向所有的IP地址发送消息
m_sockServerAddr.sin_port = htons(8222);

4.绑定服务器

if (bind(ServerSocket,(LPSOCKADDR)&m_sockServerAddr,sizeof(m_sockServerAddr)) == SOCKET_ERROR)
{
	error = _T("无法绑定服务器socket!");
	return FALSE;
}

int bind(int sockfd, const struct sockaddr, socklen_t addrlen);

sockaddr第二个参数是一个指向特定协议的地址结构的指针,
addrlen第三个参数是该地址结构的长度。
对于TCP,调用bind函数可以指定一个端口号,或指定一个IP地址,也可以两者都指定,还可以都不指定。

5异步编程方法

// 产生相应传递给窗口的消息为WM_SERVER_ACCEPT ,这是自定义消息
#define WM_CLIENT_ACCEPT WM_USER+101
//绑定消息

iErrorCode = WSAAsyncSelect(ServerSocket, m_hWnd, WM_CLIENT_ACCEPT, FD_ACCEPT);
if (iErrorCode == SOCKET_ERROR)
{
	error = _T("WSAAsyncSelect设定失败!——用于连接请求的消息");
	return FALSE;
}

消息响应
ON_MESSAGE(WM_CLIENT_ACCEPT, OnAccept)
OnAccept()函数定义在下面 --请不要急哦!

6.开始监听客户连接请求

//开始监听客户连接请求

if (listen(ServerSocket, 1) == SOCKET_ERROR)
{
	list.InsertString(0, _T("服务器监听失败!"));
	return FALSE;
}

7 代码函数

注意消息定义以及消息映射如下:
#define WM_CLIENT_ACCEPT WM_USER+101
ON_MESSAGE(WM_CLIENT_ACCEPT, OnAccept)
#define WM_CLIENT_READCLOSE WM_USER+102
ON_MESSAGE(WM_CLIENT_READCLOSE, OnReadClose)

BOOL CXXXDlg::CreateServer(CString &error)
{
	WSADATA wsaData;
	int iErrorCode;
	if (WSAStartup(MAKEWORD(2, 1), &wsaData)) //调用Windows Sockets DLL
	{
		error = _T("winSock 初始化失败");
		WSACleanup();
		return FALSE;
	}

	OutputDebugString(_T("服务器开始创建SOCKET。"));
	ServerSocket = socket(PF_INET,SOCK_STREAM,0);
	if (ServerSocket == INVALID_SOCKET)
	{
		error = _T("无法创建服务器socket!");
		return FALSE;
	}
	OutputDebugString(_T("服务器创建SOCKET成功。"));
	m_sockServerAddr.sin_family = AF_INET;
	m_sockServerAddr.sin_addr.s_addr = INADDR_ANY;   //向所有的IP地址发送消息
	m_sockServerAddr.sin_port = htons(8222);

	if (bind(ServerSocket,(LPSOCKADDR)&m_sockServerAddr,sizeof(m_sockServerAddr)) == SOCKET_ERROR)
	{
		error = _T("无法绑定服务器socket!");
		return FALSE;
	}
	OutputDebugString(_T("服务器绑定SOCKET成功。"));
	iErrorCode = WSAAsyncSelect(ServerSocket, m_hWnd, WM_CLIENT_ACCEPT, FD_ACCEPT);

	if (listen(ServerSocket,1) == SOCKET_ERROR)
	{
		error = _T("无法监听服务器socket!");
		return FALSE;
	}
	OutputDebugString(_T("服务器监听SOCKET成功。"));
	return TRUE;
}
LRESULT CXXXDlg::OnAccept(WPARAM wParam, LPARAM lParam)
{//自定义接收客户机请求的消息   ON_MESSAGE(WM_CLIENT_ACCEPT,OnAccept)
	if (WSAGETSELECTERROR(lParam))
	{
		OutputDebugString( _T("进入accept失败"));
		return 0L;
	}

	if (WSAGETSELECTEVENT(lParam) == FD_ACCEPT)//如果
	{
		Client = accept(ServerSocket, (LPSOCKADDR)&m_sockServerAddr, 0);

		if (Client == INVALID_SOCKET)
		{
			OutputDebugString(_T("未接收到连接"));
			return 0L;
		}

		WSAAsyncSelect(Client, m_hWnd, WM_CLIENT_READCLOSE, FD_READ | FD_CLOSE);

		IsTrue = TRUE;
	}

	OutputDebugString(_T("有客户端连接上了服务器。"));

	return 0L;
}


LRESULT CXXXDlg::OnReadClose(WPARAM wParam, LPARAM lParam)
{//自定义的关闭与缓冲区有消息
	if (!IsTrue)
	{
		OutputDebugString( _T("有数据到达,但是没有工作站连接。"));
	}

	CString str;
	CString Error;
	Sendbuf *p_rec = NULL;
	switch (WSAGETSELECTEVENT(lParam))
	{
	case FD_READ:
		//客户端有数据会触发FD_READ消息 进行 recv()
		break;
	case FD_CLOSE:
		OutputDebugString( _T("工作站退出。");
		list.InsertString(0, str);
		closesocket(Client);
		IsTrue = FALSE;
		break;
	}
	return 0;
}
环境:Windows XP SP3、 VC++ 6.0、 Windows 2003 SDK 使用步骤: 1、下载解压之后,使用VC++ 6.0打开两个工程:一个是SocketServer和一个ClientSocket工程。 2、首先运行服务器端工程,选默认的端口1008 3、然后运行客户端工程,选默认的端口1008和默认的服务器地址 4、再运行多个客户端进程 5、如果一切正常,可以每个客户端的消息发送,我们可以在服务端和各个客户端同步看到消息 实现一个服务器对多个客户端的关键是,在服务端的使用集合CPtrList类用保存客户端的socket对象,思想与Java中的编程思想一样,只不过Java中会使用多线程技术,在Vector集合保存客户端的socket对象,而MFC框架提供了CSocket类,它是一个异步通信的类,所以看上去代码比较Java的多线程代码简单的实现了一个对多的即时通讯功能。另外,MFC提供了CSocketFile类和CArchive类与CSocket类实现了C++的网络通讯编程功能。 本示例注释非常详细,所有的辅助类都放一个util目录中,然后在工程中分了一个目录来管理这些辅助类,使用代码非常清晰。手动书写部分的代码是按Java的规范书写,当然其它代码由IDE生成的,所以是MS的风格,所以当你看代码时,只要是使用“骆驮命名法”的方法都是本人书写的功能性代码。 参看的思路:在服务端要从回调方法onAccept读起;而客户端代码主要从OnSendButton方法读起,即可理解整个代码的意思。 阅读对象:具有Java的Socket编程经验的人员,并且希望能够书写出比Java效率更高的即时通讯程序的人员
环境:Windows XP SP 3、 VC++ 6.0、 Windows Server 2003 SDK 使用步骤: 1、下载解压之后,使用VC++ 6.0 IDE打开.dws文件 2、点击“!”按钮运行程序 3、如果一切正常会出现一个对话框,然后选择下拉框中的“服务端”启动服务器进程--接着点击“监听”按钮 4、然后再点击“!”按钮运行客户端进程 5、如果一切正常,那么选择下拉框中的“客户端”启动客户端进程--接着点击“连接”按钮,让客户端连接到socket服务器 6、在客户端的“消息”栏中输入信息,然后点击“发送”按钮 7、点击服务器端进程,应该可以看见客户端发送过来的消息,然后可以在“消息”栏中输入响应信息,然后点击“发送”按钮,此时会在客户端进程中看服务器端进程响应的信息 该示例是实现了一个客户端对象对应一个服务端对象的socket的网络编程--最简单的VC++的网络编程示例。该示使用主要是自定义一个类--它继承MFC库中CAsyncSocket类,然后重写OnAccept, OnSend, OnReceive和OnClose方法来实现一对一的VC++的socket网络编程。注意:自定义类关联应用向导生成的对话框类,需要在头文件中书写语句“class CHelloSocketDlg;”,并且在.cpp文件中写入语句“#include "HelloSocketDlg.h";”,否则编译不会通过! 本示例使用Dialog模式的UI是为方便说明socket编程,在对话框类的OnInitDialog方法有初始化的成员变量的注释说明,在自定义类中的注释非常详细。本人觉得MFC使用异步通信类CAsyncSocket实现Java中的ServerSocket类和Socket类的编程效果,是非常牛的!(虽然本人认为它还封装得不够OO--因为它封装得让使用者觉得“很傻很天真”)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值