[英]C++ Socket Programming : Accept and Recv method do not block the process
我一直在创建套接字编程代码。
我实现了服务器端程序如下:
#include "Common.h"
#include "EP_Test4.h"
int main()
{
printf("Start EP3 \n");
while (1){
EP_Test4 et;
}
return 0;
}
这是一个主要代码。 正如您所看到的,代码行在 while 语句中。 在那里,一个类被调用,类中的构造函数也被调用,然后“initEntryPoint()”方法被调用。
EP_Test4::EP_Test4(){
initEntryPoint();
}
在initEntryPoint代码中,有发起socket方法(InitCtrlSocket)、接收数据方法和关闭socket方法。
void EP_Test4::initEntryPoint()
{
printf("[Waiting Restart Signal] \n");
CSocket cCtrlEpSock;
cCtrlEpSock.InitCtrlSocket();
cCtrlEpSock.RecvRestartEPMsg();
cCtrlEpSock.CloseCtrlSocket();
}
这些方法的实现如下
void CSocket::InitCtrlSocket(){
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
printf("error\r\n");
}
if ((EpCtrlServerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))<0)
{
perror("socket error : ");
exit(1);
}
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(6870);
if (bind(EpCtrlServerSocket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
{
perror("bind error: ");
exit(1);
}
if (listen(EpCtrlServerSocket, 5)<0)
{
perror("listen error : ");
exit(1);
}
EpCtrlClientSocket = accept(EpCtrlServerSocket, (struct sockaddr *)&client_addr, &clen);
}
void CSocket::RecvRestartEPMsg(){
char arrRecvCompleteMsg[50];
memset(&arrRecvCompleteMsg, 0, sizeof(arrRecvCompleteMsg));
int data_len = recv(EpCtrlClientSocket, (char*)&arrRecvCompleteMsg, sizeof(arrRecvCompleteMsg), 0);
cout << "RECV CTRL MSG : " << arrRecvCompleteMsg << endl;
}
void CSocket::CloseCtrlSocket(){
closesocket(EpCtrlServerSocket);
closesocket(EpCtrlClientSocket);
WSACleanup();
}
但是当程序执行时,accept方法和recv方法都没有等待。 因此打印的消息如下图所示重复。
有时效果很好(等待阻塞方法),有时则不然。 我不明白为什么会这样。 据我所知,accept 方法和 recv 方法是“阻塞”方法。 但是为什么这些方法有时会阻塞,有时不会?
您没有显示足够的代码来诊断您的问题。 并且您没有对accept()
或recv()
进行任何错误处理。 accept()
可能失败,然后您将无效的套接字传递给recv()
。
我要clen
猜测您的clen
变量未初始化。 如果是的话,它会产生一个随机值,导致accept()
来如果失败clen
恰好是小于sizeof(client_addr)
并取得成功,如果clen
恰好是大于或等于sizeof(client_addr)
accept()
的addrlen
参数是一个IN/OUT参数:
addrlen [输入,输出]
一个指向整数的可选指针,该整数包含由 addr 参数指向的结构的长度。...
addrlen 引用的整数最初包含 addr 指向的空间量。 返回时,它将包含返回地址的实际长度(以字节为单位)。
...
参数addr是一个结果参数,填充有连接实体的地址,如通信层所知。 addr 参数的确切格式由发生通信的地址族决定。 addrlen 是一个 value-result 参数; 它最初应该包含由 addr 指向的空间量; 返回时,它将包含返回地址的实际长度(以字节为单位)。
如果您没有正确提供输入大小, accept()
将失败:
WSAEFAULT
addrlen 参数太小或 addr 不是用户地址空间的有效部分。
试试这个:
clen = sizeof(client_addr); // <-- add this
EpCtrlClientSocket = accept(EpCtrlServerSocket, (struct sockaddr *)&client_addr, &clen);
if (EpCtrlClientSocket < 0) // <-- add this
{
perror("accept error : ");
exit(1);
}
void CSocket::RecvRestartEPMsg(){
char arrRecvCompleteMsg[50];
int data_len = recv(EpCtrlClientSocket, arrRecvCompleteMsg, sizeof(arrRecvCompleteMsg), 0);
if (data_len > 0) // <-- add this
{
cout << "RECV CTRL MSG : ";
cout.write(arrRecvCompleteMsg, data_len);
cout << endl;
}
else
cout << "RECV CTRL ERR : " << endl;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.