Witam
Nie potrafię zamknąć połączenia close() tak aby po zakończeniu procesów gdy wydam polecenie "netstat -a" to port nie był w stanie TIME_WAIT. W necie jakiś gość pisał że najpierw należy zamknąć klienta a potem serwer. Jednak po poszperaniu w necie stwierdzam że to nieprawda, zamykanie możesz rozpocząć od dowolnego endpointu. W każdym razie jak zamkniesz od strony endpointu A to on wysyla FIN i oczekuje ACKa. Potem jak zamykasz od strony endpointu B to on też wysyła FIN i oczekuje ACKa. Troche bezsensu bo przecież jak ma mu węzeł A odpowiedzieć jak już się zamknął. Co do SO_LINGER, ustawianie tutaj czekania na np. 10 [s] zamiast domyslnie 4 minut piszą w necie że jest to workaround i powinno sie taką implementację zrobić by połączenie poprawnie się zamknęło. Ja tego nie potrafię
void freeSockets(int sockfd, int sockfdClient=-1)
{
close(sockfdClient);
close(sockfd);
}
#ifdef LINUX_USED
short unsigned int SERVER_PORT = 3000;
void sockStreamAfInetExample()
{
pid_t pid = fork();
if(!pid) //Child process Server
{
socklen_t len;
int sockfdClient = -1;
sockaddr_in clientaddr;
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd == -1)
{
perror("Unable to create AF_INET socket");
exit(EXIT_FAILURE);
}
else
std::cout << "Server::socket created succesfull on sock fd = " << sockfd << endl;
int on = 1;
if(setsockopt (sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) == -1)
{
perror("setsockopt(SO_REUSEADDR) failed");
exit(EXIT_FAILURE);
}
//The typical reason to set a SO_LINGER timeout of zero is to avoid large numbers of connections sitting in the TIME_WAIT state,
// tying up all the available resources on a server
/*linger lin;
lin.l_onoff=1;
lin.l_linger=10; // wait 10 seconds after closesocket
//how that socket should behave when data is queued to be sent and the closesocket function is called on the socket.
if(setsockopt(sockfd, SOL_SOCKET, SO_LINGER, (void*)(&lin), sizeof(lin)) == -1)
{
perror("setsockopt(SO_LINGER) failed");
exit(EXIT_FAILURE);
}*/
sockaddr_in serveraddr = {};
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); //all available interfaces //inet_addr("127.0.0.1"); //htonl(INADDR_LOOPBACK);
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(SERVER_PORT);
if (bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(sockaddr_in)) == -1)
{
perror("Server bind failed");
freeSockets(sockfd, sockfdClient);
exit(EXIT_FAILURE);
}
if (listen(sockfd, 128) == -1)//128 queue size (max number of client connections in pending state on acceptance)
{
perror("Server listen failed");
freeSockets(sockfd, sockfdClient);
exit(EXIT_FAILURE);
}
while (1)
{
cout << "Server ready to accept next connection" << endl;
//accept client connection and remove from queue
len = sizeof(sockaddr_in);
sockfdClient = accept(sockfd, (struct sockaddr *)&clientaddr, &len);
if (sockfdClient == -1)
{
perror("Cannot accept socket");
freeSockets(sockfd, sockfdClient);
exit(EXIT_FAILURE);
}
cout << "Connection accepted from client" << endl;
//Receive data from client
string buff(1000, '\0'); //goto cannot cross initialized variables
int bytes = read(sockfdClient, &buff[0], buff.size());
if (bytes == -1)
{
perror("recv failed");
freeSockets(sockfd, sockfdClient);
exit(EXIT_FAILURE);
}
cout << "Server receives " << bytes << " bytes: " << &buff[0] << endl;
break;
}
this_thread::sleep_for(chrono::seconds(2));
freeSockets(sockfd, sockfdClient);
cout << "Server closed" << endl;
this_thread::sleep_for(chrono::seconds(2)); //maybe wait some time
exit(0);
}
else //Parent process Client
{
int sockfd = -1;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1)
{
perror("Cannot create client socket");
exit(EXIT_FAILURE);
}
this_thread::sleep_for(chrono::seconds(1));
sockaddr_in serveraddr = {};
serveraddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); //htonl(INADDR_ANY); //all available interfaces //inet_addr("127.0.0.1"); //htonl(INADDR_LOOPBACK);
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(SERVER_PORT);
if (connect(sockfd, (struct sockaddr *)&serveraddr, sizeof(sockaddr_in)) == -1)
{
perror("Connect failed");
freeSockets(sockfd);
exit(0);
}
else
std::cout << "Client::connect succesfull on sock fd = " << sockfd << endl;
std::array<string, 10> table =
{
"Msg priority 0",
"Msg priority 1",
"Msg priority 2",
"Msg priority 3",
"Msg priority 4",
"Msg priority 5",
"Msg priority 6",
"Msg priority 7",
"Msg priority 8",
"Msg priority 9"
};
for (int i = 0; i<1; ++i) //the message will be delivered as one without boundaries
{
//this_thread::sleep_for(chrono::seconds(5)); //each time close, socket creation and connect is required
int bytes = write(sockfd, table.at(i).c_str(), table.at(i).size());
if (bytes == -1)
{
perror("Client write error");
freeSockets(sockfd);
exit(0);
}
cout << "Client sent " << bytes << " bytes: " << table.at(i).c_str() << endl;
}
freeSockets(sockfd);
cout << "Client closed" << endl;
int status = 0;
wait(&status);
}
}