Kirjautuminen

Haku

Tehtävät

Keskustelu: Koodit: C++: Socket Luokka *nixille

tesmu [05.06.2007 21:00:16]

#

Elikkäs socket luokka *nixille. Helpottaa kummasti sokettien käyttöä. Käytetty systeemin soketteja.

#include <stdio.h>
#include <iostream>
#include <string>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <signal.h>
#include <sys/poll.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define SOCK_SERVER 1
#define SOCK_CLIENT 0
using namespace std;
using std::string;
int BUFFER_SIZE=1000;
class Socket {                //Socket luokka
    int fd;
     struct hostent *he;
    int clilen;
    int nfd;
        struct sockaddr_in server, cli;
    socklen_t clientlen;
    string host;
    int pport;
    int stype;            //muutamia tarvittavia muuttujia
public:
    int Setinfo(string hostname, int port);
    int Connect();
    void Disconnect();
    void Senddata(string data);
    string Receive_nowait();
    string Receive_wait();
    string Gethost();
    int Getport();
    int Listen();
    int Accept();
    void Settype(int tp);
    void Setbuffer(int size_t);        //Funktioitten määrittelyt
};
void Socket::Setbuffer(int size_t) {        //Asetetaan maksimi merkkien määrä jota voidaan receivaa
    BUFFER_SIZE = size_t;
}
string Socket::Gethost() {            //Palautetaan asetettu hostname
    return host;
}
void Socket::Settype(int tp) {            //Asetetaan soketin tyyppi (SOCK_SERVER tai SOCK_CLIENT)
    stype = tp;
}
int Socket::Getport() {                //Palautetaan asetettu portti
    return pport;
}
void Socket::Disconnect() {            //Suljetaan soketti
    if (stype == 0) {            //Jos on SOCK_CLIENT (0)
        close(fd);
    }
    else {
        if (stype == 1) {        //jos on SOCK_SERVER (1)
            close(nfd);
            close(fd);
        }
    }
}
void Socket::Senddata(string data) {
    if (stype == 0) {
        send(fd,data.c_str(),data.length(),0);    //Lähetetään dataa
    }
    else {
        if (stype == 1) {

            send(nfd,data.c_str(), data.length(), 0); //Lähetetään dataa
        }
    }
}
string Socket::Receive_nowait() {
    char buffer[BUFFER_SIZE];
    string ret;
    memset( buffer, '\0', BUFFER_SIZE );
    if (stype == 0) {
            recv(fd, buffer, BUFFER_SIZE, MSG_DONTWAIT);        //ns Ei blokkiva receive elikkä se ei odota että dataa on saatavilla
        ret.assign(buffer);
    }
    else {
        if (stype == 1) {
            recv(nfd, buffer, BUFFER_SIZE, MSG_DONTWAIT);
            ret.assign(buffer);
        }
    }
    return ret;
}
string Socket::Receive_wait() {
    char buffer[BUFFER_SIZE];
    string ret;
    memset( buffer, '\0', BUFFER_SIZE);
    if (stype == 0) {
        recv(fd, buffer, BUFFER_SIZE, 0);            //odottava receive eli odottaa niin kauan että on dataa saatavilla ja palauttaa sen
        ret.assign(buffer);
    }
    else {
        if (stype == 1) {

            recv(nfd, buffer, BUFFER_SIZE, 0);

            ret.assign(buffer);
        }
    }
    return ret;
}
int Socket::Setinfo(string hostname, int port) {
    if (stype == 0) {
    host = hostname;
    pport = port;
    if ((he = gethostbyname(hostname.c_str())) == NULL) {            //selvitetään ip hostista
        return 0;
    }
    else {
        if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {        //luodaan client soketti
            return 0;
        }
        else {
                  server.sin_family = AF_INET;
            server.sin_port = htons(port);
             server.sin_addr = *((struct in_addr *)he->h_addr);
            bzero(&(server.sin_zero), 8);
            return 1;
        }
    }
    }
    else {
        if (stype == 1) {

            if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {        //luodaan server soketti

                return 0;
            }
            else {

                bzero((char *) &server, sizeof(server));
                server.sin_family = AF_INET;
                server.sin_addr.s_addr = INADDR_ANY;
                server.sin_port = htons(port);
                return 1;
            }
        }
    }
}
int Socket::Listen() {
    if (stype == 1) {
        if (bind(fd, (struct sockaddr *) &server, sizeof(server)) < 0) {        //Bindataan soketti annettujen tietojen perusteella
            return 0;
        }
        else {
            listen(fd, 5);
            clientlen = sizeof(cli);
            return 1;

        }
    }
    else {
        return 0;
    }
}
int Socket::Accept() {
    nfd = accept(fd,(struct sockaddr *) &cli, &clientlen);                //Hyväksytään yhteys jos sellainen on
    if  (nfd < 0) {
        return 0;
    }
    else {
        return 1;
    }
}
int Socket::Connect() {
    if (stype == 0) {
        if(connect(fd, (struct sockaddr *)&server, sizeof(struct sockaddr)) == -1) {    //Yhdistetään osoitteeseen
                 return 0;
            }
        else {
            return 1;
        }
    }
    else {
        return 0;
    }
}

Serveri

#include <iostream>
#include "socket.hpp"
using namespace std;

int main(void) {
    Socket s;
    s.Settype(SOCK_SERVER);
    s.Setinfo("0.0.0.0",1337);
    s.Listen();
    while (1) {
        if (s.Accept()) {
            s.Senddata("Data\n");
            cout << s.Receive_wait() << "\n";
        }
    }
}

Asiakasohjelma

#include <iostream>
#include "socket.hpp"
using namespace std;

int main(void) {
    Socket c;
    c.Settype(SOCK_CLIENT);
    c.Setinfo("127.0.0.1",1337);
    c.Connect();
    c.Senddata("MUAHAHAA");
    cout << c.Receive_wait() << "\n";
}

Metabolix [07.06.2007 11:52:34]

#

Hieman sekava tuo on, sekä kommenttien asetteluun että kirjoittamiseen voisi käyttää hieman enemmän aikaa. Omalla rivillään ne olisivat selkeämmin. Lisäksi esimerkkiohjelmassasi taitaa palvelimen puolella olla virhe, et varmaankaan halua funktion osoitetta kirjoittaa virtaan (jos se edes kelpaa coutille). Olisi myös luultavasti järkevää laittaa Receive_wait ja Receive_nowait yhdeksi funktioksi, jolle annetaan parametrina tuo odotus; nythän tuolla on kaksi lähes identtistä funktiota. Käyttämistäsi otsikoistakin vain neljä näyttäisi olevan tarpeellisia, ja kaiken kukkuraksi koodisi ei ole edes validia C++:aa:

g++ -std=c++98 kirjoitti:

In member function 'std::string Socket::Receive_nowait()':
error: ISO C++ forbids variable-size array 'buffer'
In member function 'std::string Socket::Receive_wait()':
error: ISO C++ forbids variable-size array 'buffer'
In member function 'int Socket::Setinfo(std::string, int)':
warning: control reaches end of non-void function

Tuossa lainauksessa näkyy myös toinen ongelma, joka panee epäilemään koodin toimivuutta. Vaikka stype ei periaatteessa voi ollakaan muu kuin 0 tai 1, sen tietäminen vaatii perehtymistä koodiin.

Mutta edellisestä jatkaakseni: Tuollainen globaalin muuttujan ja ei-inline-jäsenfunktioiden määrittely otsikossa ei ole lainkaan toimivaa, jos otsikkoa olisi tarkoitus käyttää useammassakin projektin tiedostossa. Ja minkä takia yhden socketin puskurin koon muuttaminen muuttaa kaikkien ohjelman sockettien puskureita? Mielenkiintoista myös valita tuolla size_t parametrin nimeksi, tyyppinä se olisi paljon loogisempi...

tesmu [07.06.2007 16:14:24]

#

Joo eli siis Receive_wait(); sen pitäisi olla

moptim [13.06.2007 19:49:55]

#

Kiitos. Nyt ircbottia väsäämään :)

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta