Ubuntu Suomen keskustelualueet
Ubuntun käyttö => Ohjelmointi, palvelimet ja muu edistyneempi käyttö => Aiheen aloitti: teele - 05.04.21 - klo:10.53
-
Löysin netistä palvelinohjeen, mutta esimerkiksi
write(new_socket , message , strlen(message));
tuottaa ongelmia, kun kutsuvassa ohjelmassa message on
char *message;
Mikä olisi oikea ratkaisu tällaisiin tilanteisiin, jos halutaan pitää pedantic-kääntäjäasetus päällä. Tai olisko olemassa joku uudempi malliohjelma, jossa asia olisi jo otettu huomioon.
Kokeiltava malliohjelma myserver07.cpp on tällainen
// haettu sivulta
// https://www.binarytides.com/socket-programming-c-linux-tutorial/
#include<stdio.h>
#include<sys/socket.h>
#include<arpa/inet.h> //inet_addr
/*
näin saadaan asiakkaan osoite, jos tarvitaan
char *client_ip = inet_ntoa(client.sin_addr);
int client_port = ntohs(client.sin_port);
*/
#include<stdio.h>
#include<string.h> //strlen
#include<stdlib.h> //strlen
#include<sys/socket.h>
#include<arpa/inet.h> //inet_addr
#include<unistd.h> //write
#include<pthread.h> //for threading , link with lpthread
void *connection_handler(void *);
int main(int argc , char *argv[])
{
int socket_desc , new_socket , c , *new_sock;
struct sockaddr_in server , client;
char *message;
//constexpr const char *message; // ei toimi
//Create socket
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
if (socket_desc == -1)
{
printf("Could not create socket");
}
//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( 8888 );
//Bind
if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
{
puts("bind failed");
return 1;
}
puts("bind done");
//Listen
listen(socket_desc , 3);
//Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);
while( (new_socket = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c)) )
{
puts("Connection accepted");
//Reply to the client
//message = "Hello Client , I have received your connection. And now I will assign a handler for you\n";
// write(new_socket , message , strlen(message)); // oli näin alkuresäisssä
write(new_socket , "kokeilua " , strlen(message)); // varoituksia tästäkin
pthread_t sniffer_thread;
new_sock = (int*)malloc(1); // lisätty (int*) -muunnos, pedantic hyväksyy
*new_sock = new_socket;
if( pthread_create( &sniffer_thread , NULL , connection_handler , (void*) new_sock) < 0)
{
perror("could not create thread");
return 1;
}
//Now join the thread , so that we dont terminate before the thread
//pthread_join( sniffer_thread , NULL);
puts("Handler assigned");
}
if (new_socket<0)
{
perror("accept failed");
return 1;
}
return 0;
}
/*
* This will handle connection for each client
* */
void *connection_handler(void *socket_desc)
{
//Get the socket descriptor
int sock = *(int*)socket_desc;
int read_size;
char *message , client_message[2000];
//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 repeat what you type \n";
write(sock , message , strlen(message));
//Receive a message from client
while( (read_size = recv(sock , client_message , 2000 , 0)) > 0 )
{
//Send the message back to client
write(sock , client_message , strlen(client_message));
}
if(read_size == 0)
{
puts("Client disconnected");
fflush(stdout);
}
else if(read_size == -1)
{
perror("recv failed");
}
//Free the socket pointer
free(socket_desc);
return 0;
}
// g++ myserver07.cpp -o myserver07 -std=c++17 -Wall -lpthread -pedantic
Virheilmoitukset ovat
g++ myserver07.cpp -o myserver07 -std=c++17 -Wall -lpthread -pedantic
myserver07.cpp: In function ‘void* connection_handler(void*)’:
myserver07.cpp:110:12: warning: ISO C++ forbids converting a string constant to ‘char*’ [-Wwrite-strings]
110 | message = "Greetings! I am your connection handler\n";
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
myserver07.cpp:113:12: warning: ISO C++ forbids converting a string constant to ‘char*’ [-Wwrite-strings]
113 | message = "Now type something and i shall repeat what you type \n";
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
myserver07.cpp: In function ‘int main(int, char**)’:
myserver07.cpp:72:8: warning: ‘message’ may be used uninitialized in this function [-Wmaybe-uninitialized]
72 | write(new_socket , "kokeilua " , strlen(message));
| ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
Kun message-muuttuja tyyppimuunnettiin
message = const_cast<char *> ("Greetings! I am your connection handler\n");
varoitukset katosivat. Kokeilematta on, toimiiko ohjelma vielä aina oikein tai olisiko muuttuja message olla jo alusta asti const char * , mikä ei ainakaan vielä ole varmaa.
-
Merkkijonoliteraalit (eli koodissa määritellyt tekstit) pitää sijoittaa const char * -tyyppiseen muuttujaan, koska tällaisen merkkijonon sisältöä ei saa muokata suorituksen aikana. Se johtaisi kääntäjästä ja käyttöjärjestelmästä riippuen virheeseen tai mahdollisesti muuhun määrittelemättömään tilanteeseen. Linuxissa literaalit sijoitetaan muistialueelle, joka on merkitty vain luettavaksi, ja kirjoitusyritys aiheuttaa segmentation faultin.
Eli määrittele const char *message:
const char *message = "Hello Client , I have received your connection. And now I will assign a handler for you\n";
write(new_socket, message, strlen(message));
Jos tekstejä on useampia, sijoita kukin omaan muuttujaansa tai vaikka taulukkoon.
const char *message1 = "Greetings! I am your connection handler\n";
write(sock, message1, strlen(message1));
const char *message2 = "Now type something and i shall repeat what you type \n";
write(sock, message2, strlen(message2));
Ohjelman connection handlerissa olisi syytä käyttää strlen-funtion sijaan read_sizea viestin koon asettamiseen. recv ei lisää viestin perään nollatavua, jolloin strlen sekoaa, jos välillä saadaan pidempiä ja välillä lyhyempiä viestejä.
while((read_size = recv(sock, client_message, 2000, 0)) > 0 )
{
//Send the message back to client
write(sock, client_message, read_size);
}
Ohjelma on puhdasta C-koodia, joten se kannattaisi kääntää g++:n sijaan gcc:llä:
gcc myserver07.c -o myserver07 -std=c99 -Wall -lpthread -pedantic
-
Taas hyvät ohjeet, kiitos :)