客户端发送的 C++ 数据无法正确到达服务器
C++ data sent by client doesn't reach server correctly
我有两个程序:客户端和服务器。这两个程序使用相同的函数来发送和接收数据。我的服务器有时收不到客户端发送的数据(在同一台机器上都是运行)。我的协议功能:
void sendString(int fd, string str) //for sending strings
{
unsigned long sz = str.size()+1;
int res = write(fd, &sz, sizeof(sz));
if (res == -1)
throw ProtocolException("SENDSTRING SEND SIZE TROUBLE");
res = write(fd, (void *)str.c_str(), sz);
if (res == -1)
throw ProtocolException("SENDSTRING SEND STRING TROUBLE");
}
void sendFlag(int fd, MessageType flag)
{
write(fd, (void *)&flag, sizeof(MessageType));
}
string receiveString(int fd)
{
unsigned long sz = 0;
int readVal;
if((readVal = read(fd, &sz, sizeof(sz))) <= 0){
cout << "Read string size trouble " << readVal << endl;
throw ProtocolException("Read string size trouble");
}
char *buf = new char[sz];
buf[sz - 1] = '[=10=]';
if((readVal = read(fd, buf, sz)) <= 0){
cout << "Read chars trouble " << readVal << endl;
}
string res(buf);
delete[] buf;
return res;
}
MessageType receiveFlag(int fd)
{
MessageType flag;
read(fd, &flag, sizeof(flag));
return flag;
}
当客户端在第一次失败后尝试登录服务器时会出现此错误。登录功能:
客户端
string receiveOKError(){
switch(receiveFlag(sd)){
case MessageType::OK: return receiveString(sd) + "\n";
case MessageType::ERROR: return "ERROR: " + receiveString(sd) + "\n";
}
}
string sendLogin(string usrname, string password)
{
sendFlag(sd, MessageType::LOGIN);
sendString(sd, usrname);
sendString(sd, password);
return receiveOKError();
}
Server(注意:MessageType::LOGIN 在服务器端调用登录函数之前通过 receiveFlag 匹配)
void sendError(int fd, string message)
{
cout << message;
sendFlag(fd, MessageType::ERROR);
sendString(fd, message);
}
void sendConfirm(int fd, string message)
{
cout << message;
sendFlag(fd, MessageType::OK);
sendString(fd, message);
}
void executeLogin(int fd, ClientPoll & worker){ // server function
string username = receiveString(fd);
string password = receiveString(fd);
if(dbManager.isRegistered(username)){
ClientInfo *cl = dbManager.getClient(username, password);
if(cl != nullptr){
//unimportant code
sendConfirm(fd, "Successful login");
}
else
sendError(fd, "Wrong password");
}
else
sendError(fd, "User doesn't exist.");
}
服务器在第二次登录尝试接收到第一个字符串时抛出 ProtocolException。服务器使用带轮询的非阻塞套接字,客户端使用阻塞套接字。
似乎与非阻塞套接字一起使用的 read() 和 write() 函数根本不会等待数据 read/written 即使您确定数据会在他们的电话,所以将他们封闭在一个 while 循环中解决了这个问题:
while(read(fd, &flag, sizeof(flag))==-1);
检查 0 值并关闭连接也很有用,因为当客户端断开连接时这些功能 return 0。
int sz;
while((sz = read(fd, &flag, sizeof(flag))) <= 0)
if(sz == 0){
//close fd or throw an exception
}
我有两个程序:客户端和服务器。这两个程序使用相同的函数来发送和接收数据。我的服务器有时收不到客户端发送的数据(在同一台机器上都是运行)。我的协议功能:
void sendString(int fd, string str) //for sending strings
{
unsigned long sz = str.size()+1;
int res = write(fd, &sz, sizeof(sz));
if (res == -1)
throw ProtocolException("SENDSTRING SEND SIZE TROUBLE");
res = write(fd, (void *)str.c_str(), sz);
if (res == -1)
throw ProtocolException("SENDSTRING SEND STRING TROUBLE");
}
void sendFlag(int fd, MessageType flag)
{
write(fd, (void *)&flag, sizeof(MessageType));
}
string receiveString(int fd)
{
unsigned long sz = 0;
int readVal;
if((readVal = read(fd, &sz, sizeof(sz))) <= 0){
cout << "Read string size trouble " << readVal << endl;
throw ProtocolException("Read string size trouble");
}
char *buf = new char[sz];
buf[sz - 1] = '[=10=]';
if((readVal = read(fd, buf, sz)) <= 0){
cout << "Read chars trouble " << readVal << endl;
}
string res(buf);
delete[] buf;
return res;
}
MessageType receiveFlag(int fd)
{
MessageType flag;
read(fd, &flag, sizeof(flag));
return flag;
}
当客户端在第一次失败后尝试登录服务器时会出现此错误。登录功能:
客户端
string receiveOKError(){
switch(receiveFlag(sd)){
case MessageType::OK: return receiveString(sd) + "\n";
case MessageType::ERROR: return "ERROR: " + receiveString(sd) + "\n";
}
}
string sendLogin(string usrname, string password)
{
sendFlag(sd, MessageType::LOGIN);
sendString(sd, usrname);
sendString(sd, password);
return receiveOKError();
}
Server(注意:MessageType::LOGIN 在服务器端调用登录函数之前通过 receiveFlag 匹配)
void sendError(int fd, string message)
{
cout << message;
sendFlag(fd, MessageType::ERROR);
sendString(fd, message);
}
void sendConfirm(int fd, string message)
{
cout << message;
sendFlag(fd, MessageType::OK);
sendString(fd, message);
}
void executeLogin(int fd, ClientPoll & worker){ // server function
string username = receiveString(fd);
string password = receiveString(fd);
if(dbManager.isRegistered(username)){
ClientInfo *cl = dbManager.getClient(username, password);
if(cl != nullptr){
//unimportant code
sendConfirm(fd, "Successful login");
}
else
sendError(fd, "Wrong password");
}
else
sendError(fd, "User doesn't exist.");
}
服务器在第二次登录尝试接收到第一个字符串时抛出 ProtocolException。服务器使用带轮询的非阻塞套接字,客户端使用阻塞套接字。
似乎与非阻塞套接字一起使用的 read() 和 write() 函数根本不会等待数据 read/written 即使您确定数据会在他们的电话,所以将他们封闭在一个 while 循环中解决了这个问题:
while(read(fd, &flag, sizeof(flag))==-1);
检查 0 值并关闭连接也很有用,因为当客户端断开连接时这些功能 return 0。
int sz;
while((sz = read(fd, &flag, sizeof(flag))) <= 0)
if(sz == 0){
//close fd or throw an exception
}