我出于教育目的而实现服务器/客户端应用程序。我的服务器打开一个套接字,并对其进行轮询以进行连接。如果有可用的连接,它将接受并发送一些数据。然后它等待输入并再次发送一些数据。
在实现客户端时,我尝试立即写入套接字,但这没有用。我必须先接收服务器告诉我的内容,然后再发送一些数据。然后等待再次接收。
这似乎不是一个好的解决方案,并且由于这是一个教育性项目,所以我想知道如何将其抽象化(即不在乎服务器将向我发送内容的次数以及我将其发送回去的次数。 )
到目前为止,我已经尝试过循环以接收服务器的输入,但是没有成功。服务器向套接字写入两次,因此客户端在尝试发送自己的消息之前必须读取两次。如果我第三次阅读,则阅读会阻塞(我认为这是正常行为)。
我尝试从客户端使用套接字上的poll来监视POLLOUT事件,但这似乎不起作用。
int connect(){
unsigned int backlog = 10;
/*
struct sockaddr_in {
short sin_family; // e.g. AF_INET
unsigned short sin_port; // e.g. htons(3490)
struct in_addr sin_addr; // see struct in_addr, below
char sin_zero[8]; // zero this if you want to
};
struct in_addr {
unsigned long s_addr; // load with inet_aton()
};
*/
struct sockaddr_in server{};
//Create socket
listeningSocket = socket(AF_INET, SOCK_STREAM, 0);
if (listeningSocket == -1) {
spdlog::critical("Could not create socket");
}
spdlog::debug("Socket created.");
//Prepare the socket for incoming connections
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(PortNumber); // NOLINT(hicpp-signed-bitwise)
if (bind(listeningSocket, (const struct sockaddr *) &server, sizeof(sockaddr_in)) < 0) {
spdlog::critical("bind failed. Error");
exit(-1);
}
spdlog::debug("Bind succeeded\n");
if (!listen(listeningSocket, static_cast<int>(backlog))) {
return listeningSocket;
}
return -1;
}
处理消息
void* sendMessage(){
//Get the socket descriptor
int sock = socket;
int read_size;
const char *message;
char client_message[200];
//Send some messages to the client
message = "Greetings! I am your connection handler\n";
write(sock, message, strlen(message));
message = "Now type something and i shall apply the caesar cipher to it \n";
write(sock, message, strlen(message));
//Receive a message from client
while ((read_size = recv(sock, client_message, 200, 0)) > 0) {
//end of string marker
client_message[read_size] = '\0';
std::string temp(client_message);
temp = cipher->operate(temp);
//Send the message back to client
write(sock, temp.c_str(), strlen(temp.c_str()));
//clear the message buffer
memset(client_message, 0, 200);
}
if (read_size == 0) {
spdlog::debug("Client disconnected");
fflush(stdout);
} else if (read_size == -1) {
spdlog::error("recv failed: {}",errno);
}
return nullptr;
}
对于客户端:
//Connect to the server
void connect()
{
struct hostent *he;
struct sockaddr_in their_addr{}; /* connector's address information */
if ((he=gethostbyname(mHost.c_str())) == nullptr) { /* get the host info */
spdlog::error("gethostbyname");
}
if ((mSocket = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
spdlog::error("socket");
exit(1);
}
their_addr.sin_family = AF_INET; /* host byte order */
their_addr.sin_port = htons(mPort); /* short, network byte order */ //NOLINT
their_addr.sin_addr = *((struct in_addr *)he->h_addr);
bzero(&(their_addr.sin_zero), 8); /* zero the rest of the struct */
if (connect(mSocket, (struct sockaddr *)&their_addr, sizeof(struct sockaddr)) == -1) {
spdlog::error("connect");
exit(1);
}
}
}
并尝试发送消息:
void sendMessage(){
#define MAX 100
if (!sockfd) {
sockfd = mSocket;
spdlog::info("Setting socket to {}", sockfd);
}
char buff[MAX];
struct pollfd fds[1];
fds[0].fd=sockfd;
while (( recv(sockfd, buff, 200, 0)) > 0) {
printf("From Server : %s", buff);
bzero(buff, sizeof(buff));
}
strcpy(buff, "PAPARI");
write(sockfd, buff, sizeof(buff));
bzero(buff, sizeof(buff));
read(sockfd, buff, sizeof(buff));
printf("From Server : %s", buff);
close(sockfd);
}
这将在客户端收到来自服务器的两条消息后阻塞。