Kirjoittaja Aihe: [ratkaistu] char*, char[], const char[] ongelmia socket-funktioiden kanssa  (Luettu 2133 kertaa)

teele

  • Käyttäjä
  • Viestejä: 850
    • Profiili
Löysin netistä palvelinohjeen, mutta esimerkiksi

Koodia: [Valitse]
write(new_socket , message , strlen(message));

tuottaa ongelmia, kun kutsuvassa ohjelmassa message on

Koodia: [Valitse]
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

Koodia: [Valitse]

// 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

Koodia: [Valitse]
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));
      |   ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

« Viimeksi muokattu: 05.04.21 - klo:17.50 kirjoittanut teele »

teele

  • Käyttäjä
  • Viestejä: 850
    • Profiili

Kun message-muuttuja tyyppimuunnettiin

Koodia: [Valitse]
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.

nm

  • Käyttäjä
  • Viestejä: 16425
    • Profiili
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:

Koodia: [Valitse]
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.

Koodia: [Valitse]
        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ä.

Koodia: [Valitse]
        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ä:

Koodia: [Valitse]
gcc myserver07.c -o myserver07 -std=c99 -Wall -lpthread -pedantic

teele

  • Käyttäjä
  • Viestejä: 850
    • Profiili

Taas hyvät ohjeet, kiitos  :)