Próbuję wykonać próbkę serwera w języku C++ przy użyciu <sys/socket.h>
i konstruktora GUI Qt Creator, ale dwa dziwne zachowania występują w warstwie gniazda programu. Po pierwsze, ja uruchomić serwer, ale przy pierwszej próbie robię aby połączyć go za pomocą telnet
jest imediately zamknięteGniazdo C++ zamykające pierwszą próbę połączenia
Trying 127.0.0.1 ... Connected
do 127.0.0.1.
Znak ucieczki to "^]".
Połączenie zamknięte przez hosta zagranicznego.
Kiedy próbuję połączyć się po raz drugi, działa i terminal czeka na moje wejście. Drugą rzeczą jest, gdy zamykam połączenie. Gdybym ponownie uruchomić zaraz po, w ciągu kilku minut, program zatrzymuje się na bind
wyjściu i powrocie:
błąd na wiązanie: Address already in use
Więc przypuszczam, może połączenie odbywa się po tym, jak go złamam, używając funkcji onCortarConexao()
lub po prostu zatrzymania debuggera. W każdym razie, czego mi brakuje?
Mój kod:
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
Na MainWindow.cpp: Klasa
void MainWindow::on_pushButton_clicked()
{
socket1 = new MSocket();
socket1->start();
}
void MainWindow::on_pushButton_3_clicked()
{
socket1->onCortarConexao();
}
Gniazdo: realizacja
#ifndef MSOCKET_H
#define MSOCKET_H
#include <QString>
#include <QObject>
#include <QThread>
#include <QList>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#define SERVER_BUFFER 4096
#define PORTRUN 15000
class MSocket : public QThread
{
public:
MSocket();
void error(char *msg);
void onCortarConexao();
private:
int sockfd;
int newsockfd;
int portno;
int clilen;
int n;
char buffer[SERVER_BUFFER];
struct sockaddr_in serv_addr, cli_addr;
u_short port;
void run();
};
#endif // MSOCKET_H
Gniazdo:
void MSocket::run()
{
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0){
error("ERROR opening socket");
exit(-1);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = PORTRUN;
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(portno);
serv_addr.sin_addr.s_addr = INADDR_ANY;
fprintf(stdout,"Iniciando servidor..");
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0){
error("ERROR on binding");
exit(-1);
}
listen(sockfd,5);
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, (socklen_t*) sizeof(cli_addr));
if (newsockfd < 0){
error("ERROR on accept");
exit(-1);
}
bzero(buffer,SERVER_BUFFER);
n = read(newsockfd,buffer,SERVER_BUFFER-1);
if (n < 0)
error("ERROR reading from socket");
printf("Here is the message: %s",buffer);
n = write(newsockfd,"I got your message",18);
if (n < 0)
error("ERROR writing to socket");
}
void MSocket::onCortarConexao(){
printf("Encerrando socket");
close(newsockfd);
close(sockfd);
}
Kompletny kod jest pod adresem: https://github.com/FabioNevesRezende/BasicCppServer
Edit 1:
Więc this lista pakietów komunikacji między telnet i mojej aplikacji Qt Server można graphicaly widać w WireShark (plik .pcapng). Zawiera 11 klatek. Sześć pierwszych pochodzi z pierwszego telnetu, gdy jest on natychmiast zamykany. Jak się wydaje na klatkach 4 i 5, gdzie aplikacja wysyła [FIN, ACK]
, a serwer odpowiada na nią, zamykając połączenie. Ramki 7, 8, 9 są drugą próbą połączenia, a ramki 10 i 11 są wysyłane do serwera przez serwer abc
. Jak na ekranie wydruku:
Problem polega na tym, że nie wiem, dlaczego aplikacja wysyła ten FIN
i gdzie w kodzie jest.
Podany przez Ciebie link do projektu github jest uszkodzony. Bez tego nie mogę stwierdzić, czy to, co masz na myśli przez drugą próbę, to po prostu próbować ponownie po stronie klienta lub zrestartować serwer. Czy mógłbyś wyjaśnić? – lasaro
Przepraszam, jest ponownie włączony. – Fabiotk