Я внедряю приложение сервер / клиент для образовательных целей. Мой сервер открывает сокет и опрашивает его на предмет соединений. Если соединение доступно, оно принимает его и отправляет некоторые данные. Затем он ожидает ввода и снова отправляет некоторые данные.
При реализации на стороне клиента я сразу попытался записать в сокет, но это не сработало. Я должен был сначала получить то, что сервер сказал мне, а затем отправить ему некоторые данные. Тогда ждите, чтобы получить снова.
Это не кажется хорошим решением, и, поскольку это образовательный проект, мне было интересно, как бы я сделал его абстрактным (т.е. не заботился о том, сколько раз сервер отправлял мне что-то, и я отправлял что-то обратно. )
До сих пор я пытался зациклить, чтобы получить входные данные сервера, но безуспешно. Сервер дважды пишет в сокет, поэтому клиент должен дважды прочитать, прежде чем пытаться отправить собственное сообщение. Если я в третий раз читаю блоки чтения (что я считаю нормальным поведением).
Я пытался использовать опрос на сокете со стороны клиента для отслеживания событий 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);
}
Блокируется после получения клиентом двух сообщений от сервера.