c++中socket的接受,用什么方式,比如用到什么函数,怎么个解决思路?谢谢高手指教。
最好就是一个解决问题的比较详细的思路以及框架结构。由于我是新手所以对这个语言也不是很熟悉,所以,还需要大家的比较认真的说明,谢谢了!要是有好的学习这个语言的方法,也可以推...
最好就是一个解决问题的比较详细的思路以及框架结构。由于我是新手所以对这个语言也不是很熟悉,所以,还需要大家的比较认真的说明,谢谢了!要是有好的学习这个语言的方法,也可以推荐给我。我万分感谢。
展开
3个回答
展开全部
Socket编程首先要包含所需的头文件Winsock2.h并工程中添加库文件ws2_32.lib.
接着加载套接字库所用函数是
WSAStartup( wVersionRequested, &wsaData ); 第一个参数代表的是所要加载的套接字库的版本,第二个参数用于存储返回的版本信息
wVersionRequested = MAKEWORD( 1, 1 );用MAKEWORD来设置版本号的值其中地位代表主版本号
TCP编程:
服务器端的编写:
1. 创建套接字
SOCKET socketSrc = socket(AF_INET, SOCK_STREAM, 0);
第一个参数:指定地址族在1.1版本中只能使用AF_INET
第二个参数:指定套接字的类型在1.1版本中指定指定两种一SOCK_STREAM流式套接字和SOCK_DREAM数据报套接字
第三个参数:指示所要使用的的协议,如果为0则自动选择合适的协议(推荐)
2. 绑定套接字
bind(socketSrc, (SOCKADDR*)&addsrc, sizeof(SOCKADDR));
第一个参数:一个未绑定的的套接字
第二个参数:通过一个SOCKADDR结构体将一个地址分配给套接字
第三个参数:第二个参数的大小长度
SOCKADDR结构体: struct sockaddr_in {
short sin_family;
u_short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
第一个成员:sin_family地址族(这个参数不使用网络字节序列,其他参数都是网络字节序列)
第二个成员:sin_port指定要绑定的端口使用htons来转换成网络字节序列因为是无符号短整型
第三个成员:in_addr的结构体用来存放地址in_addr的结构如下
struct in_addr {
union {
struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;
struct { u_short s_w1,s_w2; } S_un_w;
u_long S_addr;
} S_un;
};
可以看出in_addr是一个包含一个联合体的结构体,联合体可以用来存放不同类型的数据但只存放一个数据,根据选择不同而不同,我们的程序中选择的是长整型的变量S_addr来存放一个地址需用htonl来转换成为网络字节序;
l htonl和htons区别是在于一个是将一个32位的主机字节序列转换成32位的TCP/IP的网络字节序一个则是16位
l inet_addr的用处是将一个点分制的IP地址字符串转换为一个合适的 in_addr的变量。
l inet_ntoa将一个网络地址转换为标准的点分式地址格式的字符串
3. 监听套接字:
listen(socketSrc, 5); //listen用于将一个已绑定但未连接的套接字对象设定成监听模式等 到一个即将到来的连接
第二个参数:表示等待连接的最大长度,如果参数被设置为SOMAXCONN将被设成一个最大的可能值
4. 接受连接:
在一个被设置为监听的套接字上允许一个连接,并返回一个已连接的新的套接字
SOCKET socketconn = accept(socketSrc, (SOCKADDR*)&addclient, &len);
第一个参数:一个被设置为监听状态的套接字;
第二个参数:一个SOCKADDR结构体用于保存请求连接的实体的地址,根据地址族的不同所创建的结构体不一样
第三个参数:存储地址的长度,此参数在调用accept函数前必须初始化,否则会导致调用失败
5. 完成以上工作后通过recv和send函数来接收和发送数据
recv(socketconn, recvbuf, 100, 0);
第一个参数是一个已连接的套接字
第二个参数是用来存储接收的数据的缓冲区地址
第三个参数表示缓冲区的大小
第四个参数指示接收的模式此处设为0
客户端的编写
6. 首先也是创建套接字
7. 然后在建立连接
connect(sockclient, (SOCKADDR*)&addsrc, sizeof(SOCKADDR));
第二个参数是要连接的地址,第三个参数则是地址的大小
UDP编程部分在简单的多线程聊天室的编写中详细说明
他是基于无连接的协议
所以编写服务器端时只要绑定了套接字后就可以开始传送和接受数据,而客户端则只需创建套接字就可以开始传送和接收
同过 recvfrom和sendto函数来操作
使用closesocket(m_socket);关闭一个套接字,使用WSACleanup();来释放套接字库
希望对你有帮助呵呵 这是在VC下的
接着加载套接字库所用函数是
WSAStartup( wVersionRequested, &wsaData ); 第一个参数代表的是所要加载的套接字库的版本,第二个参数用于存储返回的版本信息
wVersionRequested = MAKEWORD( 1, 1 );用MAKEWORD来设置版本号的值其中地位代表主版本号
TCP编程:
服务器端的编写:
1. 创建套接字
SOCKET socketSrc = socket(AF_INET, SOCK_STREAM, 0);
第一个参数:指定地址族在1.1版本中只能使用AF_INET
第二个参数:指定套接字的类型在1.1版本中指定指定两种一SOCK_STREAM流式套接字和SOCK_DREAM数据报套接字
第三个参数:指示所要使用的的协议,如果为0则自动选择合适的协议(推荐)
2. 绑定套接字
bind(socketSrc, (SOCKADDR*)&addsrc, sizeof(SOCKADDR));
第一个参数:一个未绑定的的套接字
第二个参数:通过一个SOCKADDR结构体将一个地址分配给套接字
第三个参数:第二个参数的大小长度
SOCKADDR结构体: struct sockaddr_in {
short sin_family;
u_short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
第一个成员:sin_family地址族(这个参数不使用网络字节序列,其他参数都是网络字节序列)
第二个成员:sin_port指定要绑定的端口使用htons来转换成网络字节序列因为是无符号短整型
第三个成员:in_addr的结构体用来存放地址in_addr的结构如下
struct in_addr {
union {
struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;
struct { u_short s_w1,s_w2; } S_un_w;
u_long S_addr;
} S_un;
};
可以看出in_addr是一个包含一个联合体的结构体,联合体可以用来存放不同类型的数据但只存放一个数据,根据选择不同而不同,我们的程序中选择的是长整型的变量S_addr来存放一个地址需用htonl来转换成为网络字节序;
l htonl和htons区别是在于一个是将一个32位的主机字节序列转换成32位的TCP/IP的网络字节序一个则是16位
l inet_addr的用处是将一个点分制的IP地址字符串转换为一个合适的 in_addr的变量。
l inet_ntoa将一个网络地址转换为标准的点分式地址格式的字符串
3. 监听套接字:
listen(socketSrc, 5); //listen用于将一个已绑定但未连接的套接字对象设定成监听模式等 到一个即将到来的连接
第二个参数:表示等待连接的最大长度,如果参数被设置为SOMAXCONN将被设成一个最大的可能值
4. 接受连接:
在一个被设置为监听的套接字上允许一个连接,并返回一个已连接的新的套接字
SOCKET socketconn = accept(socketSrc, (SOCKADDR*)&addclient, &len);
第一个参数:一个被设置为监听状态的套接字;
第二个参数:一个SOCKADDR结构体用于保存请求连接的实体的地址,根据地址族的不同所创建的结构体不一样
第三个参数:存储地址的长度,此参数在调用accept函数前必须初始化,否则会导致调用失败
5. 完成以上工作后通过recv和send函数来接收和发送数据
recv(socketconn, recvbuf, 100, 0);
第一个参数是一个已连接的套接字
第二个参数是用来存储接收的数据的缓冲区地址
第三个参数表示缓冲区的大小
第四个参数指示接收的模式此处设为0
客户端的编写
6. 首先也是创建套接字
7. 然后在建立连接
connect(sockclient, (SOCKADDR*)&addsrc, sizeof(SOCKADDR));
第二个参数是要连接的地址,第三个参数则是地址的大小
UDP编程部分在简单的多线程聊天室的编写中详细说明
他是基于无连接的协议
所以编写服务器端时只要绑定了套接字后就可以开始传送和接受数据,而客户端则只需创建套接字就可以开始传送和接收
同过 recvfrom和sendto函数来操作
使用closesocket(m_socket);关闭一个套接字,使用WSACleanup();来释放套接字库
希望对你有帮助呵呵 这是在VC下的
展开全部
最简单的就是send receive函数了,绑定好IP,建立好连接,两端就可以通信了
本回答被网友采纳
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
展开全部
朋友!!!我感觉应该如下
CSocket是MFC在CAsyncSocket基础上派生的一个同步阻塞Socket的封装类。它是如何又把CAsyncSocket变成同步的,而且还能响应同样的Socket事件呢? 其实很简单,CSocket在Connect()返回WSAEWOULDBLOCK错误时,不是在OnConnect(),OnReceive()这些事件终端函数里去等待。你先必须明白Socket事件是如何到达这些事件函数里的。这些事件处理函数是CSocketWnd窗口对象回调的,而窗口对象收到来自Socket的事件,又是靠线程消息队列分发过来的。总之,Socket事件首先是作为一个消息发给CSocketWnd窗口对象,这个消息肯定需要经过线程消息队列的分发,最终CSocketWnd窗口对象收到这些消息就调用相应的回调函数(OnConnect()等)。 所以,CSocket在调用Connect()之后,如果返回一个WSAEWOULDBLOCK错误时,它马上调用一个用于提取消息的函数PumpMessage(...),就是从当前线程的消息队列里取关心的消息. PumnMessage会遇到下面几种情况: 1 提取出了(从消息队列中移出来Remove),用户正在使用的一个Socket发送的WM_SOCKET_NOTIFY消息和对应的 FD_XXX事件,返回True. 2 提取出了(从消息队列中移出来Remove),用户正在使用的一个Socket发送的WM_SOCKET_NOTIFY消息和对应的 FD_Close事件,返回True. 3 提取出了(从消息队列中移出来Remove),PumpMessage(..)设定的定时器的WM_TIMER消息,TimeOut事件为 CSocket的一个成员变量,m_nTimeOut=2000ms,返回True 4 用户调用了CancelBlockingCall() 设置错误代码为WSAEINTR(被中断了),返回False 5 用户一直没有取到用户正在使用的一个Socket发送的WM_SOCKET_NOTIFY消息和对应的FD_XXX事件,但是取到 了同一个线程中的其他Socket的WM_SOCKET_NOTIFY消息及其对应的消息,则将这些消息,加入到一个辅助性 的队列中去,以后处理. 6 没有取到任何WM_SOCKET_NOTIFY消息,则开始查看(不是取出来,而是查看)本线程的消息队列中是否有其他 消息,如果有的话,调用虚函数OnMessagePending(),来处理这些消息(OnMessagePending()用户可以自定义 在阻塞时,用户想要处理的消息),如果没有,则调用WaitMessage()开始等待消息的到来. 代码说明如下: A 先看Connect,因为Connect的阻塞的实现和Accept,Receive,ReceiveFrom,Send,SendTo都有点不同. 也许你们会奇怪为何是ConnectHelper(...),而不是Connect(...).其实ConnectHelper(...)才是Connect(..) 真正调用的东西,如下: BOOL CAsyncSocket::Connect(const SOCKADDR* lpSockAddr, int nSockAddrLen) //ConnectHelper( ... )为一虚函数 //继承自CAsyncSocket,Csocket有重新定义过. //这也是为什么CSocket是Public继承的原因 BOOL CSocket::ConnectHelper( ... ) } //end while } return false; } return true; } //在PumpMessages中会设置一个定时器,时间为m_nTimeOut=2000ms //当在这个时间之内,依然没有得到消息的话,就返回 BOOL CSocket::PumpMessages( UINT uStopFlag ) //这个是PumpMessage的第1种情况 if(WSAGETSELECTEVENT(msg.lParam) == uStopFlag ) } //这个是PumpMessage的第5种情况 if (msg.wParam != 0 || msg.lParam != 0) CSocket::AuxQueueAdd(msg.message, msg.wParam, msg.lParam); } //这个是PumpMessage的第3种情况 else if (::PeekMessage(&msg, pState->m_hSocketWindow,WM_TIMER, WM_TIMER, PM_REMOVE)) //这个是PumpMessage的第6种情况 if (bPeek && ::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) else } }//end while ////这个是PumpMessage的第4种情况 if (!bBlocking) m_pbBlocking = NULL; //将WM_SOCKET_NOTIFY消息发送到Creat CSocketWnd线程的消息队列中 //以便处理其他的Socket消息 ::PostMessage(pState->m_hSocketWindow, WM_SOCKET_NOTIFY, 0, 0); return TRUE; } B 再看Receive(..) //其实CSocket的这种实现方式决定了,应用程序不能够在一个线程中Create一个socket, //然后创建一个新的线程来专门Receive,因为这个新的线程将永远不能取到FD_Read的事件, //因为并不是在这个线程中创建的CSocketWnd对象,它无法接受到发送到CSocketWnd的消息 //(在Windows中接受消息的主体是窗口) //Receive和Connect的实现方式的最大区别为 //Connect 是不断的调用PumpMessage(..) //而Receive则不断的调用自身 int CSocket::Receive(void* lpBuf, int nBufLen, int nFlags) int nResult; while ((nResult = CAsyncSocket::Receive(lpBuf, nBufLen, nFlags)) == SOCKET_ERROR) else return SOCKET_ERROR; } return nResult; } 最后,总结一下自己对CSocket的看法, 1 虽然它解决了结束阻塞线程的方法,调用CancelBlockingCall,但是多线程模式根本就不适合于CSocket 2 CSocket和CAsyncSocket利用Windows的消息模式将前台的界面处理和后台的网络通信都整合到消息传递模型 下,但是很明显,一旦后台的网络过于繁忙,则前台的处理可能就无法顾及,所以CSocket也就只能小打小闹
建议你多看MSDN,上面说的清楚,和孙鑫的VC++视频!!
CSocket是MFC在CAsyncSocket基础上派生的一个同步阻塞Socket的封装类。它是如何又把CAsyncSocket变成同步的,而且还能响应同样的Socket事件呢? 其实很简单,CSocket在Connect()返回WSAEWOULDBLOCK错误时,不是在OnConnect(),OnReceive()这些事件终端函数里去等待。你先必须明白Socket事件是如何到达这些事件函数里的。这些事件处理函数是CSocketWnd窗口对象回调的,而窗口对象收到来自Socket的事件,又是靠线程消息队列分发过来的。总之,Socket事件首先是作为一个消息发给CSocketWnd窗口对象,这个消息肯定需要经过线程消息队列的分发,最终CSocketWnd窗口对象收到这些消息就调用相应的回调函数(OnConnect()等)。 所以,CSocket在调用Connect()之后,如果返回一个WSAEWOULDBLOCK错误时,它马上调用一个用于提取消息的函数PumpMessage(...),就是从当前线程的消息队列里取关心的消息. PumnMessage会遇到下面几种情况: 1 提取出了(从消息队列中移出来Remove),用户正在使用的一个Socket发送的WM_SOCKET_NOTIFY消息和对应的 FD_XXX事件,返回True. 2 提取出了(从消息队列中移出来Remove),用户正在使用的一个Socket发送的WM_SOCKET_NOTIFY消息和对应的 FD_Close事件,返回True. 3 提取出了(从消息队列中移出来Remove),PumpMessage(..)设定的定时器的WM_TIMER消息,TimeOut事件为 CSocket的一个成员变量,m_nTimeOut=2000ms,返回True 4 用户调用了CancelBlockingCall() 设置错误代码为WSAEINTR(被中断了),返回False 5 用户一直没有取到用户正在使用的一个Socket发送的WM_SOCKET_NOTIFY消息和对应的FD_XXX事件,但是取到 了同一个线程中的其他Socket的WM_SOCKET_NOTIFY消息及其对应的消息,则将这些消息,加入到一个辅助性 的队列中去,以后处理. 6 没有取到任何WM_SOCKET_NOTIFY消息,则开始查看(不是取出来,而是查看)本线程的消息队列中是否有其他 消息,如果有的话,调用虚函数OnMessagePending(),来处理这些消息(OnMessagePending()用户可以自定义 在阻塞时,用户想要处理的消息),如果没有,则调用WaitMessage()开始等待消息的到来. 代码说明如下: A 先看Connect,因为Connect的阻塞的实现和Accept,Receive,ReceiveFrom,Send,SendTo都有点不同. 也许你们会奇怪为何是ConnectHelper(...),而不是Connect(...).其实ConnectHelper(...)才是Connect(..) 真正调用的东西,如下: BOOL CAsyncSocket::Connect(const SOCKADDR* lpSockAddr, int nSockAddrLen) //ConnectHelper( ... )为一虚函数 //继承自CAsyncSocket,Csocket有重新定义过. //这也是为什么CSocket是Public继承的原因 BOOL CSocket::ConnectHelper( ... ) } //end while } return false; } return true; } //在PumpMessages中会设置一个定时器,时间为m_nTimeOut=2000ms //当在这个时间之内,依然没有得到消息的话,就返回 BOOL CSocket::PumpMessages( UINT uStopFlag ) //这个是PumpMessage的第1种情况 if(WSAGETSELECTEVENT(msg.lParam) == uStopFlag ) } //这个是PumpMessage的第5种情况 if (msg.wParam != 0 || msg.lParam != 0) CSocket::AuxQueueAdd(msg.message, msg.wParam, msg.lParam); } //这个是PumpMessage的第3种情况 else if (::PeekMessage(&msg, pState->m_hSocketWindow,WM_TIMER, WM_TIMER, PM_REMOVE)) //这个是PumpMessage的第6种情况 if (bPeek && ::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) else } }//end while ////这个是PumpMessage的第4种情况 if (!bBlocking) m_pbBlocking = NULL; //将WM_SOCKET_NOTIFY消息发送到Creat CSocketWnd线程的消息队列中 //以便处理其他的Socket消息 ::PostMessage(pState->m_hSocketWindow, WM_SOCKET_NOTIFY, 0, 0); return TRUE; } B 再看Receive(..) //其实CSocket的这种实现方式决定了,应用程序不能够在一个线程中Create一个socket, //然后创建一个新的线程来专门Receive,因为这个新的线程将永远不能取到FD_Read的事件, //因为并不是在这个线程中创建的CSocketWnd对象,它无法接受到发送到CSocketWnd的消息 //(在Windows中接受消息的主体是窗口) //Receive和Connect的实现方式的最大区别为 //Connect 是不断的调用PumpMessage(..) //而Receive则不断的调用自身 int CSocket::Receive(void* lpBuf, int nBufLen, int nFlags) int nResult; while ((nResult = CAsyncSocket::Receive(lpBuf, nBufLen, nFlags)) == SOCKET_ERROR) else return SOCKET_ERROR; } return nResult; } 最后,总结一下自己对CSocket的看法, 1 虽然它解决了结束阻塞线程的方法,调用CancelBlockingCall,但是多线程模式根本就不适合于CSocket 2 CSocket和CAsyncSocket利用Windows的消息模式将前台的界面处理和后台的网络通信都整合到消息传递模型 下,但是很明显,一旦后台的网络过于繁忙,则前台的处理可能就无法顾及,所以CSocket也就只能小打小闹
建议你多看MSDN,上面说的清楚,和孙鑫的VC++视频!!
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询