我正致力于实现C ++客户端服务器聊天程序,以了解更多/练习套接字编程。我使用的是winsockV2。
简言之, 客户端程序连接到服务器,该服务器将客户端套接字存储在向量中 客户端程序为服务器发送消息以分发给向量中的其他客户端。
我认为我遇到的问题是客户端和服务器正在接收消息并将其存储在char message[256]
中,如果消息短于256,则在{I}时显示奇怪的字符我被告知的{1}}是未初始化的记忆。这是输出的一个例子:
std::cout << message;
是否有某种方法可以创建接收邮件大小的字符数组?即
k:message from client to other client╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠(■o
否则您对char recvMessage[4096];
int s = recv(socket, recvMessage, sizeof(recvMessage),0);
char recvOutput[strlen(recvMessage)] = recvMessage;
std::cout << recvOutput << std::endl;
消息的解决方案是什么,您不知道其长度?
如果我是一个完全白痴,请善待,我来自PHP。课程如下:
查看recv
和receiveMessages()
函数
distributeMessages()
查看#include "stdafx.h"
#include "svr.h"
svr::svr()
{
//WSA Business I don't understand
WORD wVersionRequested;
WSADATA wsaData;
int err;
/* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
wVersionRequested = MAKEWORD(2, 2);
err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0)
{
/* Tell the user that we could not find a usable */
/* Winsock DLL. */
printf("WSAStartup failed with error: %d\n", err);
}
//End of WSA Business
//get addressSize
addressSize = sizeof(address);
//set address data members
address.sin_family = AF_INET;
address.sin_port = htons(444);
address.sin_addr.s_addr = INADDR_ANY;
//init sListen
sListen = socket(AF_INET, SOCK_STREAM, 0);
bind(sListen, (sockaddr*)&address, addressSize);
}
svr::~svr()
{
}
void svr::start()
{
std::thread newConnThread(&svr::newConnection, this);
newConnThread.join();
}
void svr::receiveMessages(int clientIndex)
{
std::cout << "\tsvr::recv thread started for client index:" << clientIndex << std::endl;
//create char arr
char recvMessage[256];
//forever
while (true)
{
//receive message and input it to recvMessage char arr.
recv(clients[clientIndex], recvMessage, sizeof(recvMessage), 0);
//if message is not null, send out to other clients
if (recvMessage != NULL)
{
std::cout << "\t\tINFO:Received message of length: " << std::strlen(recvMessage) << " size: " << sizeof(recvMessage) << " : " << recvMessage << std::endl;
distributeMessages(recvMessage, clientIndex);
}
}
}
//distributes messages to all clients in vector. called by receiveMessages function, normally in rMessages thread.
void svr::distributeMessages(std::string message, int clientIndex)
{
for (unsigned int i = 0; i < clients.size(); i++)
{
if (clientIndex != i)
{
send(clients[i], message.c_str(), message.length(), 0);
}
else
{
//would have sent to self, not useful.
}
}
}
//accepts new connections and adds sockets to vector.
void svr::newConnection()
{
//mark for accept, unsure of somaxconn value;
listen(sListen, SOMAXCONN);
std::cout << "\tSERVER: awaiting new connections..." << std::endl;
while (true)
{
//accept connection and push on to vector.
clients.push_back(accept(sListen, (sockaddr*)&address, &addressSize));
//responds to new clients.
const char *message = "Hi, you've successfully connected!";
int clientIndex = clients.size() - 1;
int sent = send(clients[clientIndex], message, 33, 0);
//start new receiveMessage thread
std::thread newClient(&svr::receiveMessages, this, clientIndex);
//detach here, let newConn thread operate without depending on receiveMessages
newClient.detach();
}
std::cout << "\tSERVER: no longer listening for new connections" << std::endl;
}
和cSend()
函数
cRecv()
答案 0 :(得分:4)
你的recv消息解决方案是什么,你不知道 长度?
recv()
告诉您收到的邮件的长度。你不必怀疑它是什么。这是recv()
的返回值。
int s = recv(socket, recvMessage, sizeof(recvMessage),0);
看 - 你走了。它就在你面前。它是s
。当然,如果有错误s
将是否定的,您需要检查它。但是,忽略那些细节,你的担忧就结束了:s
是你收到的信息的长度。
char recvOutput[strlen(recvMessage)] = recvMessage;
那不行。 strlen()
在这做什么? strlen()
计算字符串的大小,期望字符串是一个老式的C风格字符串,以\0
字节结束。 recv()
不会终止使用\0
字节收到的任何内容。相反,它返回实际的字符数。
此外,无论如何,这还不行。你无法通过这种方式初始化数组。
显然,你明显的意图是期望收到一个文本字符串作为消息。好吧,既然你选择的语言是C++
,并且你标记了你的问题,那么合乎逻辑的结论就是你应该使用C++
给你处理文本字符串的内容:{{1} } class:
std::string
你去吧。任务完成。由于您已经知道std::string recvOutput{recvMessage, recvMessage+s};
中收到的邮件的长度,正如我们之前确定的那样(并且在仔细检查s
不是否定之后),您只需使用{{1}现有的构造函数初始化新字符串给定一个迭代器或指针,指向字符串的开头和结尾。
在处理低级操作系统接口(如套接字)时,您别无选择,只能使用原始数据类型,例如普通s
数组和缓冲区,因为这是操作的唯一内容系统理解。但是,使用C ++库提供的丰富的模板和类,您的代码应该在第一时间切换到使用C ++类和模板,以便能够使用所有这些资源。因此,只要您确定了文本字符串std::string
刚刚提出的大小,只需将其填入char
,然后再确定如何处理它。