论坛首页 入门技术论坛

MFC之Socket服务端编程

浏览 8087 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2014-03-01  

       这些天由于工作需要,需要用到MFC的Socket编程,于是和这个许久未见的老朋友C++又有了接触,虽然彼此有些生疏,但还算顺利,哈哈。。。。,经过百度谷歌一番,着实发现资料很多,但是有些会将我们带入误区,特别如果你是个初学者。所以就自己这次的经验总结下吧,闲着也是闲着。

       一、假如你是个初学者,那就让我们先了解了解Socket的一些基本知识

       1、什么是TCP/IP、UDP?

       TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制协议/网间协议,是一个工业标准的协议集,它是为广域网(WANs)设计的。

  UDP(User Data Protocol,用户数据报协议)是与TCP相对应的协议。它是属于TCP/IP协议族中的一种。

       2 、TCP/IP、UDP之间的区别

       A、TCP是面向连接的传输控制协议,而UDP提供了无连接的数据报服务;
       B、TCP具有高可靠性,确保传输数据的正确性,不出现丢失或乱序;UDP在传输数据前不建立连接,不对数据报进行检查与修改,无须等待对方的应答,所以会出现分组丢失、重复、乱序,应用程序需要负责传输可靠性方面的所有工作;
       C、也正因为以上特征,UDP具有较好的实时性,工作效率较TCP协议高;
       D、UDP段结构比TCP的段结构简单,因此网络开销也小。

       3、Socket是什么?

       Socket熟称“套接字”,是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面(Facade)模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。     

       4、Socket编程有哪些类型?

       常用的Socket类型有:SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等等。这里主要讲下SOCK_STREAM和SOCK_DGRAM,其中SOCK_STREAM是基于TCP/IP协议传输的,SOCK_DGRAM就是基于UDP的,两张协议不可相互通信,所以在创建Socket的时候要注意,服务端和客户端要采用同一种协议。

       二、Socket服务端,启动Socket和监听客户端的连接

BOOL CPostClientDlg::InitSocket()
{
	//m_socket=socket(AF_INET,SOCK_DGRAM,0); //基于udp
	m_socket=socket(AF_INET,SOCK_STREAM,0);//基于tcp
	
	if(INVALID_SOCKET==m_socket)
	{
		MessageBox("套接字创建失败!");
		return FALSE;
	}
	SOCKADDR_IN addrSock;
	addrSock.sin_family=AF_INET;
	addrSock.sin_port=htons(6000);
	addrSock.sin_addr.S_un.S_addr=htonl(INADDR_ANY);

	int retval;
	retval=bind(m_socket,(SOCKADDR*)&addrSock,sizeof(SOCKADDR));
	
	if(SOCKET_ERROR==retval)
	{
		closesocket(m_socket);
		MessageBox("绑定失败!");
		return FALSE;
	}

	//创建一线程监听
	RECVPARAM *pRecvParam=new RECVPARAM;
	pRecvParam->sock=m_socket;
	pRecvParam->hwnd=m_hWnd;
	HANDLE hThread=CreateThread(NULL,0,RecvProc,(LPVOID)pRecvParam,0,NULL);
	CloseHandle(hThread);
	
	return TRUE;
}

 

DWORD WINAPI CPostClientDlg::RecvProc(LPVOID lpParameter)
{
	SOCKET sock=((RECVPARAM*)lpParameter)->sock;
	HWND hwnd=((RECVPARAM*)lpParameter)->hwnd;
	delete lpParameter;	//释放内存的操作
	
	if(listen(sock,5) == SOCKET_ERROR)
    	{
    	    //监听客户端,如果是基于UDP的,则不需要listen
	    return 0;
    	} 

	SOCKADDR_IN addrFrom;
	int len=sizeof(SOCKADDR);

	char recvBuf[200]={0};//获取客户端发送的消息
	int retval;
	while(TRUE)
	{
		SOCKET ConnectSocket = accept(sock,(sockaddr*)&addrFrom,&len); //得到客户端的IP地址。 
		retval=recv(ConnectSocket,recvBuf,200,0); 
		if(SOCKET_ERROR==retval)
			break;

	}
	return 0;
}

 其中结构体RECVPARAM定义如下:

struct RECVPARAM
{
 SOCKET sock;
 HWND hwnd;
};

 

 就这么简单,服务端就ok了。

 之前在网上看到的大部门创建服务端的Socket的基本上都是在主线程里加监听,犹如

BOOL CPostClientDlg::InitSocket()
{
	//m_socket=socket(AF_INET,SOCK_DGRAM,0); //基于udp
	m_socket=socket(AF_INET,SOCK_STREAM,0);//基于tcp
	
	if(INVALID_SOCKET==m_socket)
	{
		MessageBox("套接字创建失败!");
		return FALSE;
	}
	SOCKADDR_IN addrSock;
	addrSock.sin_family=AF_INET;
	addrSock.sin_port=htons(6000);
	addrSock.sin_addr.S_un.S_addr=htonl(INADDR_ANY);

	int retval;
	retval=bind(m_socket,(SOCKADDR*)&addrSock,sizeof(SOCKADDR));
	
	if(SOCKET_ERROR==retval)
	{
		closesocket(m_socket);
		MessageBox("绑定失败!");
		return FALSE;
	}

	//监听
	if(listen(m_socket,5) == SOCKET_ERROR)
    	{
    	    //监听客户端,如果是基于UDP的,则不需要listen
	    return FALSE;
    	} 
	while(TRUE)
	{
		SOCKET ConnectSocket = accept(m_socket,(sockaddr*)&addrFrom,&len); //得到客户端的IP地址。 
		.....

	}
	
	return TRUE;
}

 

这样会导致主线程得不到释放程序会假死现象。

当然这是比较原始的Socket编程了,现在对Socket封装的类也有很多,编程起来也很方便,比如用的比较多的是CAsyncSocket,CSocket等等,但是如果要学习的话还是原始的好,毕竟被包装过的,看不到他的真面目,哈哈!

       服务端创建Socket就这么简单,希望对你有所帮助!

 

 

 

 

 

 

 

论坛首页 入门技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics