gpt4 book ai didi

C++,接受后无法接收数据和无效套接字

转载 作者:行者123 更新时间:2023-11-30 02:30:46 25 4
gpt4 key购买 nike

我写了一个 POSIX-BSD Socket [Listener-Client],但我遇到了问题。我认为我的代码有问题,但我无法意识到问题出在哪里。我的操作系统是 Windows 10 64 位。我在本地主机上创建一个带有 EServer 类的监听器,我尝试通过 ESocket 连接到这个监听器。连接后,我可以将数据从 ESocket 发送到服务器套接字,但我无法在服务器套接字中接收它。而且,下一个传入连接将出现 INVALID_SOCKET 错误。这是我的代码:

----------------EServer.h-----------------

#ifndef ESERVER_H
#define ESERVER_H


#include <string>
#include <stdio.h>
#include <cstring>
#include <ESocket.h>

using namespace std;

#ifdef _WIN32
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0501
#endif
#include <winsock2.h>
#include <Ws2tcpip.h>
#else
typedef int SOCKET;
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <fcntl.h>
#endif


class EServer
{
public:
EServer(int port);
virtual ~EServer();
int Destruct();
int Close();
bool isListening();
ESocket AcceptClient();

protected:

private:
};

#endif // ESERVER_H




----------------EServer.cpp-----------------

#include "EServer.h"
#include "stdio.h"



SOCKET sx = NULL;

EServer::EServer(int port)
{
struct sockaddr_in server;
//Create a socket
if((sx = socket(AF_INET , SOCK_STREAM , 0 )) < 0)
{
sx = NULL;
return;
}



server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( port );

//Bind
if( bind(sx ,(struct sockaddr *)&server , sizeof(server)) < 0)
{
sx = NULL;
return;
}

printf("Listening status: %i\r\n",listen(sx,100));
}

EServer::~EServer()
{
Destruct();
}


bool EServer::isListening()
{
return (sx != NULL);
}


ESocket EServer::AcceptClient()
{
struct sockaddr_in client;
SOCKET new_socket;

#ifdef _WIN32
int c = sizeof(struct sockaddr_in);
new_socket = accept(sx , (struct sockaddr *)&client, &c);
if (new_socket == INVALID_SOCKET)
{
printf("Invalid");
}
#else
socklen_t c = sizeof(struct sockaddr_in);
new_socket = accept(sx , (struct sockaddr *)&client, &c);
if (new_socket < 0)
{
}
#endif


return ESocket(new_socket);
}

int EServer::Destruct()
{
#ifdef _WIN32
return WSACleanup();
#else
return 0;
#endif
}



int EServer::Close()
{


int status = 0;
#ifdef _WIN32
status = shutdown(sx, SD_BOTH);
if (status == 0) { status = closesocket(sx); }
#else
status = shutdown(sx, SHUT_RDWR);
if (status == 0) { status = close(sx); }
#endif

return status;

}


---------------ESocket.h-------------------


#ifndef ESOCKET_H
#define ESOCKET_H

#include <string>
#include <stdio.h>
#include <cstring>

using namespace std;

#ifdef _WIN32
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0501
#endif
#include <winsock2.h>
#else
typedef int SOCKET;
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <fcntl.h>
#endif

class ESocket
{
public:
ESocket(string ip,int port);
ESocket(SOCKET e);
virtual ~ESocket();
int Destruct();
int Close();
int setAsNonBlock();
bool SendData(string data);
bool isConnected();

string ReceiveData(int len);

static int Init()
{
#ifdef _WIN32
WSADATA wsa_data;
return WSAStartup(MAKEWORD(1,1), &wsa_data);
#else
return 0;
#endif
}

static string getIP(char* host)
{

struct hostent *he;
struct in_addr **addr_list;

char ip[100];


int i;

if ( (he = gethostbyname( host ) ) == NULL)
{
return "";
}

addr_list = (struct in_addr **) he->h_addr_list;

for(i = 0; addr_list[i] != NULL; i++)
{

strcpy(ip , inet_ntoa(*addr_list[i]) );
}
string x = ip;
return x;
}


protected:

private:

};

#endif // ESOCKET_H






--------------------ESocket.cpp---------------

#include "ESocket.h"
#include "stdio.h"

SOCKET s = NULL;


ESocket::ESocket(string ip,int port)
{
struct sockaddr_in server;
if((s = socket(AF_INET , SOCK_STREAM , 0 )) < 0)
{
s = NULL;
}
server.sin_addr.s_addr = inet_addr(ip.c_str());
server.sin_family = AF_INET;
server.sin_port = htons( port );
if (connect(s , (struct sockaddr *)&server , sizeof(server)) < 0)
{
s = NULL;
}
}

ESocket::ESocket(SOCKET e)
{
s = e;
}

ESocket::~ESocket()
{
Destruct();
}



bool ESocket::isConnected()
{
return (s != NULL);
}



int ESocket::Destruct()
{
#ifdef _WIN32
return WSACleanup();
#else
return 0;
#endif
}



int ESocket::Close()
{


int status = 0;
#ifdef _WIN32
status = shutdown(s, SD_BOTH);
if (status == 0) { status = closesocket(s); }
#else
status = shutdown(s, SHUT_RDWR);
if (status == 0) { status = close(s); }
#endif

s = NULL;
return status;

}


bool ESocket::SendData(string data)
{

if( send(s , data.c_str() , data.length() , 0) < 0)
{
s = NULL;
return false;
}
return true;
}


string ESocket::ReceiveData(int len)
{
int recv_size;
char reply[len];
if((recv_size = recv(s , reply , len , 0)) < 0)
{
return "";
}

if (recv_size == 0)
{
s = NULL;
return "";
}
printf("%i",recv_size);
reply[recv_size] = '\0';
return reply;
}





int ESocket::setAsNonBlock()
{

int res;
#ifdef _WIN32
u_long iMode = 1;
res = ioctlsocket(s, FIONBIO, &iMode);
#else
int opts;
opts = fcntl(s, F_GETFL);
if(opts < 0)
{
res = -1;
}
opts = (opts | O_NONBLOCK);
if(fcntl(s, F_SETFL, opts) < 0)
{
res = -1;
}
#endif
return res;
}



-------------MAIN--------------

ESocket::Init();


EServer e(105);
while (e.isListening()){
ESocket x1("127.0.0.1",105);
printf("Connecting\n");
ESocket x2 = e.AcceptClient();
printf("Accepted\n");
x1.SendData("Ehem");
printf("Sent\n");
cout<<x2.ReceiveData(100);
printf("Received\n");
Sleep(2000);
}

如果有人能向我解释我该如何解决,我会很高兴。

最佳答案

问题是您对所有连接的套接字使用了一个全局变量。当您接受一个套接字时,该单个套接字将被分配给最新接受的套接字。当一个新的套接字连接被接受时,您将用新的套接字覆盖单个变量,从而失去之前的连接。

您应该将这些全局变量设为类中的私有(private)成员变量。通过这样做,SOCKET 变量对于每个 ESocket 实例的每个实例都是唯一的。


还有一些风格上的东西可以改进。我在评论中提到的一个。另一个是变量名,ssx?描述性不强,我猜你选择 sx 是因为你不能在两个源文件中都使用 s ?那应该是你做错事的迹象。


最后是它们中最主要的缺陷:你在析构函数中把地毯拉到你自己脚下。

析构函数调用 WSACleanup ,它真正清理了整个 winsocket 子系统,用链接 WSACLeanup 的话来说引用:

Sockets that were open when WSACleanup was called are reset and automatically deallocated as if closesocket were called.

这是非常有问题的,因为 EServer::AcceptClient 按值 返回新创建的套接字,这会导致创建一个临时实例并销毁。临时对象的这种破坏是导致其套接字子系统关闭的原因。从那一点开始的任何套接字操作都将导致错误。

您应该只在退出程序时调用一次 WSACleanup

如果析构函数应该做任何事情,它应该关闭套接字,但这会导致其他问题,因为您没有遵循 rule of three, five or zero .你绝对应该关注 rule of three在这里,并实现一个复制构造函数和复制赋值运算符。

关于C++,接受后无法接收数据和无效套接字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38285155/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com