我在使用C ++编程的套接字应用程序时遇到问题。我在Windows XP上使用Bloodshed Dev-Cpp进行编程。我创建了一个用于处理所有消息传输的类,并且有一个客户端和服务器程序,它们都使用该类来处理它们的服务。应用程序本身是非常基本的,我唯一的目的就是让所有这些工作起作用。
用于发送消息的客户端就像我期望的那样工作。如果我的服务器正在运行,则在发送消息时没有任何错误。如果它没有运行它将传递错误。但我的服务器不断接受奇怪的胡言乱语。它始终是相同的数据。当它收到消息时,没有任何效果。如果我有我的客户端尝试识别服务器,它会回来乱七八糟。
我在这里包含了我的源代码。链接器还引入了两个额外的参数:-lwsock32和包含Dev-Cpp附带的库libws2_32.a。
这是我的Messager类的标题:
#ifndef MESSAGER
#define MESSAGER
#include <string>
class Messager{
private:
int sendSocket;
int listenSocket;
public:
void init(void);
bool connect(std::string ip, std::string port);
bool bind(std::string port);
void listen(void);
void send(std::string message);
std::string receive(void);
};
#endif
这些是我对Messager类的定义:
#include "Messager.h"
#include <winsock2.h>
#include <sys/types.h>
#include <ws2tcpip.h>
#include <windows.h>
void Messager::init(void){
WSADATA wsaData;
WSAStartup(MAKEWORD(1,1), &wsaData);
}
bool Messager::connect(std::string ip, std::string port){
struct addrinfo hints;
struct addrinfo *res;
bool success = false;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
getaddrinfo(ip.c_str(), port.c_str(), &hints, &res);
sendSocket = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
success = ::connect(sendSocket, res->ai_addr, res->ai_addrlen) != -1;
freeaddrinfo(res);
return success;
}
bool Messager::bind(std::string port){
struct addrinfo hints, *res;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
getaddrinfo(NULL, port.c_str(), &hints, &res);
listenSocket = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if(listenSocket == INVALID_SOCKET){
return false;
}
if(::bind(listenSocket, res->ai_addr, res->ai_addrlen) == -1){
return false;
}
return true;
}
void Messager::listen(void){
::listen(listenSocket, 10);
}
int Messager::send(std::string message){
const std::string terminator = "\r\n";
std::string realMessage;
int size = 0;
int totalSent = 0;
realMessage = message;
realMessage += terminator;
size = realMessage.size();
totalSent = ::send(sendSocket, realMessage.c_str(), size, 0);
if(totalSent == 0 || totalSent == -1){
return 0; // There must be an error, 0 means it is an error
}
// This statement keeps adding the results of ::send to totalSent until it's the size of the full message
for(totalSent = 0; totalSent < size; totalSent += ::send(sendSocket, realMessage.c_str(), size, 0));
return totalSent;
}
// This function has been updated a lot thanks to @Luke
std::string Messager::receive(void){
const int bufferSize = 256;
const std::string terminator = "\r\n";
char buffer[bufferSize];
int i = 0;
int received = 0;
std::string tempString;
size_t term = 0;
for(i = 0; i < bufferSize; i++){
buffer[i] = 0;
}
received = ::recv(listenSocket, buffer, bufferSize, 0);
tempString = buffer;
term = tempString.find(terminator);
if(term != -1){ // Already have line
line = tempString;
}
while(received != -1 && received != 0){ // While it is receiving information...
// Flush the buffer
for(i = 0; i < bufferSize; i++){
buffer[i] = 0;
}
::recv(listenSocket, buffer, bufferSize, 0);
tempString += buffer;
term = tempString.find(terminator);
if(term != -1){ // Found terminator!
return tempString;
}
}
throw 0; // Didn't receive any information. Throw an error
}
任何有关可能发生的事情的想法都会非常感激。如果有必要,我可以发布服务器和客户端使用的代码,但我可以给出一个大致的概述:
服务器:
客户端:
提前致谢。
答案 0 :(得分:3)
我看到两个问题。
通常这看起来类似于以下内容(这些都来自内存所以可能存在一些小错误,但这是它的要点):
bool Message::Receive(std::string& line)
{
// look for the terminating pair in the buffer
size_t term = m_buffer.find("\r\n");
if(term != -1)
{
// already have a line in the buffer
line.assign(m_buffer, 0, term); // copy the line from the buffer
m_buffer.erase(0, term + 2); // remove the line from the buffer
return true;
}
// no terminating pair in the buffer; receive some data over the wire
char tmp[256];
int count = recv(m_socket, tmp, 256);
while(count != -1 && count != 0)
{
// successfully received some data; buffer it
m_buffer.append(tmp, count);
// see if there is now a terminating pair in the buffer
term = m_buffer.find("\r\n");
if(term != -1)
{
// we now have a line in the buffer
line.assign(m_buffer, 0, term); // copy the line from the buffer
m_buffer.erase(0, term + 2); // remove the line from the buffer
return true;
}
// we still don't have a line in the buffer; receive some more data
count = recv(m_socket, tmp, 256);
}
// failed to receive data; return failure
return false;
}
答案 1 :(得分:1)
我有点担心你的receive
代码。它创建一个char*
缓冲区来接收数据,但实际上并没有为它分配任何内存。
现在我无法判断你是否在那里调用WinSock recv
,因为你没有明确说::recv
,但我认为你需要:
malloc
分配一些空格(id recv
想要一个缓冲区);或recv
分配自己的缓冲区)。我真的很惊讶不会导致核心转储,因为当你致电buffer
时,recv
的值可以设置为任何。
这样的事可能会更好:
char *Messager::receive(void){
int newSocket = 0;
struct sockaddr_storage *senderAddress;
socklen_t addressSize;
char *buffer;
addressSize = sizeof senderAddress;
newSocket = accept(listenSocket, (struct sockaddr *)&senderAddress,
&addressSize);
buffer = new char[20];
recv(newSocket, buffer, 20, 0);
return buffer;
}
但是你需要记住,这个函数的客户端负责在缓冲区完成后释放缓冲区。
答案 2 :(得分:1)
两个建议:
答案 3 :(得分:0)
在receive
函数中,buffer
本地永远不会初始化为任何内容,因此您最终会将消息读入某些随机内存,并可能导致损坏或崩溃。您可能需要char buffer[MAX_MSG_LENGTH];
而不是char *buffer