Popiol |
Poison Headcrab |
|
|
Dołączył: 02 Lis 2005 |
Posty: 16 |
Przeczytał: 0 tematów
Ostrzeżeń: 0/5
|
Skąd: Wygiełzów |
|
|
|
|
|
|
Zamieszczam kod programiku, który realizuje prosty serwer HTTP. Coś dla miłośników socketów i programowania obiektowego.
Najpierw klasa Sockecik, która obudowuje zwykłego socketa w przydatne funkcje.
sockecik.h:
Kod: | #ifndef socketyH
#define socketyH
#include <string>
#include <winsock2.h>
using namespace std;
class Sockecik {
protected:
SOCKET s;
string wiadomosc;
public:
Sockecik(SOCKET sock = 0);
void tcpSocketInit();
void bind(string ip, int port);
void listen();
void connect(string adr, int port);
void send(string tekst);
short int recv(); //0: nic nie przeczytano; -1: zamknieto polaczenie; 1 - przeczytano cos
virtual void accept();
void serwuj();
virtual void serw();
void close();
virtual Sockecik * utworzSockecik(SOCKET sock);
~Sockecik();
};
#endif |
sockecik.cpp:
Kod: | #include <iostream>
#pragma hdrstop
#include "sockety.h"
#pragma package(smart_init)
using namespace std;
Sockecik::Sockecik(SOCKET sock) : s(sock) {
BYTE lowbyteVer = 2, highbyteVer = 0;
WORD wVersionRequested = MAKEWORD( lowbyteVer, highbyteVer );
WSADATA wsaData;
if (WSAStartup(wVersionRequested,&wsaData) != 0) {
cout << "Błąd przy WSAStartup\n";
}
if (lowbyteVer != 2 || highbyteVer != 0) {
WSACleanup();
cout << "Nie znaleziono biblioteki w wersji 2.0\n";
}
}
void Sockecik::tcpSocketInit() {
s = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if (s == INVALID_SOCKET) {
cout << "Błąd przy tworzeniu socketa\n";
}
}
void Sockecik::bind(string ip, int port) {
sockaddr_in adres;
adres.sin_family = AF_INET;
adres.sin_addr.s_addr = inet_addr(ip.c_str());
adres.sin_port = htons(port);
::bind(s, (sockaddr*)&adres, sizeof(adres));
}
void Sockecik::listen() {
::listen(s, SOMAXCONN);
}
void Sockecik::connect(string adr, int port) {
sockaddr_in adres;
adres.sin_family = AF_INET;
adres.sin_addr = *((in_addr *)gethostbyname(adr.c_str())->h_addr);
adres.sin_port = htons(port);
if (::connect(s,(SOCKADDR*)&adres,sizeof(adres)) == SOCKET_ERROR) {
cout << "Blad przy laczeniu sie z " << adr << ':' << port << '\n';
}
}
void Sockecik::send(string tekst) {
if (::send(s,tekst.c_str(),tekst.length(),0) == SOCKET_ERROR) {
cout << "Blad przy wysylaniu tekstu:" << tekst << '\n';
}
}
short int Sockecik::recv() {
int ilbajt;
char bufor[201];
wiadomosc.clear();
while (true) {
ilbajt = ::recv(s,bufor,200,0);
if (ilbajt == 0) break;
if (ilbajt == SOCKET_ERROR) {
cout << "Blad przy recv\n";
return -1;
}
bufor[ilbajt] = '\0';
wiadomosc.append(bufor);
if (ilbajt < 200) break;
}
if (wiadomosc.length() == 0) return 0;
return 1;
}
void Sockecik::close() {
if (closesocket(s) != 0) {
cout << "Blad przy zamykaniu socketa\n";
}
}
Sockecik::~Sockecik() {
close();
if (WSACleanup() != 0) {
cout << "Blad przy WSACleanup";
}
}
void Sockecik::accept() {
listen();
Sockecik * nowySerwer;
SOCKET nowySocket;
while (true) {
nowySocket = ::accept(s,NULL,NULL);
if (nowySocket != INVALID_SOCKET) {
nowySerwer = utworzSockecik(nowySocket);
nowySerwer->serwuj();
}
}
}
Sockecik * Sockecik::utworzSockecik(SOCKET sock) {
return new Sockecik(sock);
}
DWORD WINAPI serwujThread(LPVOID sockecik) {
Sockecik * sock = (Sockecik*)sockecik;
sock->serw();
return 0;
}
void Sockecik::serwuj() {
CreateThread(NULL,0,serwujThread,this,0,NULL);
}
void Sockecik::serw() {
short int result;
listen();
while (true) {
result = recv();
if (result == 1) cout << wiadomosc;
else if (result == -1) break;
}
} |
A teraz klasa SerwerHTTP, która dziedziczy po Sockecik.
serwerhttp.h:
Kod: | #ifndef socketyhttpH
#define socketyhttpH
#include "sockety.h"
class SerwerHTTP : public Sockecik {
public:
SerwerHTTP(SOCKET s, int port) : Sockecik(s) {
bind ("0", port);
}
SerwerHTTP(int port) : Sockecik() {
tcpSocketInit();
bind ("0", port);
}
SerwerHTTP(SOCKET s) : Sockecik(s) {}
void serw();
Sockecik * utworzSockecik(SOCKET sock);
};
#endif |
serwerhttp.cpp:
Kod: | #include <iostream>
#include <fstream>
#pragma hdrstop
#include "socketyhttp.h"
#pragma package(smart_init)
void dopiszInt(string& s, int i) {
char str[30]; itoa(i,str,10);
s.append(str);
}
void SerwerHTTP::serw() {
if (recv() == 1) {
wiadomosc = wiadomosc.substr(0,wiadomosc.find('\r',0));
cout << "Odebrano zapytanie:\n" << wiadomosc << '\n';
}
string komenda = wiadomosc.substr(0,wiadomosc.find(' ',0));
wiadomosc = wiadomosc.substr(wiadomosc.find(' ',0)+1,wiadomosc.length());
string nazwapliku = wiadomosc.substr(1,wiadomosc.find(' ',0)-1);
if (nazwapliku == "") nazwapliku = "index.html";
fstream plik(nazwapliku.c_str(),ios::in);
string head, body;
if (!plik.is_open()) {
body = "404 Nie ma takiego pliku";
head = "HTTP/1.1 404 Not Found\r\n"
"Connection: Keep-Alive\r\n"
"Content-Type: text/plain\r\n"
"Content-Length: ";
dopiszInt(head,body.length()); head += "\r\n";
} else {
char buf[200]; int ilbajt;
while (true) {
ilbajt = plik.readsome(buf,200);
if (ilbajt == 0) break;
body.append(buf,ilbajt);
}
plik.close();
string typ = nazwapliku.substr(nazwapliku.find('.',0)+1,nazwapliku.length());
if (typ == "txt") typ = "plain";
head = "HTTP/1.1 200 OK\r\n"
"Connection: Keep-Alive\r\n"
"Content-Type: text/";
head += typ; head += "\r\n"
"Content-Length: ";
dopiszInt(head,body.length()); head += "\r\n";
}
if (komenda == "GET") {
send(head+"\r\n"+body);
cout << "Wyslano:\n" << head << "\r\n" << body << "\n\n";
}
else if (komenda == "HEAD") {
send(head+"\r\n");
cout << "Wyslano:\n" << head << "\r\n" << "\n\n";
}
}
Sockecik * SerwerHTTP::utworzSockecik(SOCKET sock) {
return new SerwerHTTP(sock);
} |
I wreszcie program główny, który wygląda zdecydowanie najładniej:
Kod: | #include "socketyhttp.h"
SerwerHTTP serwer(4321); //parametr to numer portu
int main(int argc, char* argv[])
{
serwer.accept();
return 0;
} |
Teraz trzeba wejść do przeglądarki i napisać jako adres numer ip kompa, na którym odpaliliśmy serwer, a po numerze ip ':' i numer portu, który w tym przypadku wynosi 4321. Czyli piszemy coś w rodzaju http://123.456.0.0:4321. Jeśli ustawimy port 80 w programie to w przeglądarce nie trzeba wpisywać numeru portu, bo 80 to numer domyślny dla http. Możemy też dopisać nazwę pliku, który chcemy ściągnąć. Jeśli takiego pliku nie będzie to serwer zwróci kod 404. Ścieżką wyjściową, z której serwer pobiera pliki jest folder, w którym odpaliliśmy serwer. Miłego serfowania. |
|