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"; }
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...
Joo eli siis Receive_wait(); sen pitäisi olla
Kiitos. Nyt ircbottia väsäämään :)
Aihe on jo aika vanha, joten et voi enää vastata siihen.