您好我遇到套接字服务器和客户端问题。
问题在于,当我发送邮件的速度非常快时,邮件会混淆。当我发送它们时,我们可以说每秒1条消息,一切运行良好,但是当我每40毫秒发送一条消息时,它们会混淆起来。
这是我收到的代码:
std::string* AteneaClient::readSocket () {
std::string finalString = std::string("");
int size = MSG_SIZE;
bool receiving = true;
int timesBufferInc=0;
while (receiving) {
std::string temporalString;
//create an empty buffer
char* RCV_BUFFER = (char*) malloc (size* sizeof(char));
for(int i=0;i<size;i++){
RCV_BUFFER[i]=' ';
}
RCV_BUFFER[size-1]='\0';
int result = recv(sock,RCV_BUFFER,size-1,NULL);
if ( result== SOCKET_ERROR ) {
free(RCV_BUFFER);
return NULL;
}
else if(result<size-1){
receiving=false;
}
temporalString = std::string(RCV_BUFFER);
finalString+=temporalString;
}
return new std::string(finalString);
}
这是我的发送代码:
int sendThread(void* data){
SND_THREAD_DATA* parameters =(SND_THREAD_DATA*)data;
SOCKET* individualSocket = parameters->individualSocket;
std::string * message = parameters->message;
char RCV_BUFFER[MSG_SIZE];
std::string converter;
std::cout <<"(!)Thread: Iniciando sendThread Individual.."<<std::endl;
SOCKET default_socket = *individualSocket;
bool running=true;
while(running){
int length=message->length();
char *cstr = new char[length + 1];
strcpy(cstr, message->c_str());
if(::send(*individualSocket,cstr,length + 1,NULL)==SOCKET_ERROR){
logSendError();
running=false;
}
delete cstr;
Sleep(SLEEPTIME);
}
}
以下是我设置套接字时的代码:
void AteneaClient::startUp(){
int iResult = 0;
iResult = WSAStartup(MAKEWORD(2, 2), &WinSockData);
if (iResult != NO_ERROR) {
wprintf(L"(!)Main:WSAStartup() failed with error: %d\n", iResult);
return;
}
ADDR.sin_addr.s_addr= inet_addr(IP);
ADDR.sin_family = AF_INET;
ADDR.sin_port = htons(PORT);
sock = socket(AF_INET,SOCK_STREAM,0);
running=true;
}
任何人都知道为什么套接字消息会混淆?
谢谢!
编辑:
这是我目前收到的方法,其中包含Maxim评论的改进:
std::string* AteneaClient::readSocket () {
int HEADER_SIZE=4;
std::string finalString = std::string("");
int sizeFirstBuffer = HEADER_SIZE*sizeof(char);
char* RCV_BUFFER=(char*) malloc(sizeFirstBuffer+1);
//clean new buffer
for(int i=0;i<HEADER_SIZE;i++){
RCV_BUFFER[i]=' ';
}
RCV_BUFFER[sizeFirstBuffer]='\0';
int result = recv(sock,RCV_BUFFER,sizeFirstBuffer,NULL);
//cout << "The Size to read is:" <<RCV_BUFFER << endl;
//now i create a buffer with that size
int sizeThatIHaveToRead= atoi(RCV_BUFFER);
int sizeSecondBuffer = sizeThatIHaveToRead*sizeof(char);
char* RCV_BUFFER_SECOND=(char*) malloc(sizeSecondBuffer+1);
//clean new buffer
for(int i=0;i<sizeSecondBuffer;i++){
RCV_BUFFER_SECOND[i]=' ';
}
RCV_BUFFER_SECOND[sizeSecondBuffer]='\0';
result = recv(sock,RCV_BUFFER_SECOND,sizeSecondBuffer,NULL);
//cout << "RCV_BUFFER_SECOND:" <<RCV_BUFFER_SECOND << endl;
finalString+=RCV_BUFFER_SECOND;
return new std::string(finalString);
}
答案 0 :(得分:5)
您正在通过流套接字发送字符串,并期望它们以原子方式发送和接收,例如要么没有发送/接收,要么发送/接收整个字符串。这不是流套接字的工作方式。
流套接字通常只发送部分数据,因此您需要继续发送,直到所有数据都已发送完毕。同样是为了接收。
您还需要以某种方式界定消息,否则在接收时您将不知道消息何时结束以及下一个消息何时开始。两种最常见的方式是a)前缀消息的大小,b)使用消息分隔符(例如换行符号)。
ZeroMQ可以为您完成这两项任务:您的应用程序最终会发送和接收完整的消息,而无需在字节级别实现消息帧和发送/接收。
更新的代码仍未正确使用send
和recv
来电。
以下是发送和接收std::string
的函数的正确用法:
#include <stdexcept>
#include <stdint.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
ssize_t recv_all(int fd, void* buf, size_t buf_len) {
for(size_t len = buf_len; len;) {
ssize_t r = ::recv(fd, buf, len, 0);
if(r <= 0)
return r;
buf = static_cast<char*>(buf) + r;
len -= r;
}
return buf_len;
}
ssize_t send_all(int fd, void const* buf, size_t buf_len) {
for(size_t len = buf_len; len;) {
ssize_t r = ::send(fd, buf, len, 0);
if(r <= 0)
return r;
buf = static_cast<char const*>(buf) + r;
len -= r;
}
return buf_len;
}
void send_string(int fd, std::string const& msg) {
ssize_t r;
// Send message length.
uint32_t len = msg.size();
len = htonl(len); // In network byte order.
if((r = send_all(fd, &len, sizeof len)) < 0)
throw std::runtime_error("send_all 1");
// Send the message.
if((r = send_all(fd, msg.data(), msg.size())) < 0)
throw std::runtime_error("send_all 2");
}
std::string recv_string(int fd) {
ssize_t r;
// Receive message length in network byte order.
uint32_t len;
if((r = recv_all(fd, &len, sizeof len)) <= 0)
throw std::runtime_error("recv_all 1");
len = ntohl(len);
// Receive the message.
std::string msg(len, '\0');
if(len && (r = recv_all(fd, &msg[0], len)) <= 0)
throw std::runtime_error("recv_all 2");
return msg;
}