Browse Source

playing with python server

lookup-tables
Stephan Richter 7 years ago
parent
commit
507f36a1a7
  1. 262
      src/main.cpp
  2. 77
      src/web4rail.server.py

262
src/main.cpp

@ -1,262 +0,0 @@ @@ -1,262 +0,0 @@
#include <iostream>
#include <fstream>
#include <stdexcept> // runtime_error
#include <sstream>
#include <cstring>
#include <unistd.h>
#ifdef linux
#include <sys/socket.h> // socket(), connect()
#include <arpa/inet.h> // sockaddr_in
#include <netdb.h> // gethostbyname(), hostent
#include <errno.h> // errno
#else
#include <winsock2.h>
#endif
// erzeugt eine Exception, verwendet dabei die globale Variable errno
std::runtime_error CreateSocketError(){
std::ostringstream temp;
#ifdef linux
temp << "Socket-Fehler #" << errno << ": " << strerror(errno);
#else
int error = WSAGetLastError();
temp << "Socket-Fehler #" << error;
char* msg;
if(FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),reinterpret_cast<char*>(&msg), 0, NULL)){
try{
temp << ": " << msg;
LocalFree(msg);
}catch(...){
LocalFree(msg);
throw;
}
}
#endif
return std::runtime_error(temp.str());
}
void SendAll(int socket, const char* const buf, const int size){
int bytesSent = 0; // Anzahl Bytes die wir bereits vom Buffer gesendet haben
do{
int result = send(socket, buf + bytesSent, size - bytesSent, 0);
if(result < 0) throw CreateSocketError();
bytesSent += result;
} while(bytesSent < size);
}
// Liest eine Zeile des Sockets in einen stringstream
void GetLine(int socket, std::stringstream &line){
for(char c; recv(socket, &c, 1, 0) > 0; line << c){
if(c == '\n') return;
}
throw CreateSocketError();
}
// Entfernt das http:// vor dem URL
void RemoveHttp(std::string& url){
size_t pos = url.find("http://");
if(pos != std::string::npos) url.erase(0, 7);
}
// Gibt die Dateiendung im URL zurück
std::string GetFileEnding(std::string& URL){
using namespace std;
size_t pos = URL.rfind(".");
if(pos == string::npos)return "";
URL.erase(0, pos);
string ending = ".";
// Algorithmus um Sachen wie ?index=home nicht zuzulassen
for(string::iterator it = URL.begin() + 1; it != URL.end(); ++it){
if(isalpha(*it)){
ending += *it;
}else break;
}
return ending;
}
// Gibt den Hostnamen zurück und entfernt ihn aus der URL, sodass nur noch der Pfad übrigbleibt
std::string RemoveHostname(std::string& URL){
size_t pos = URL.find("/");
if(pos == std::string::npos){
std::string temp = URL;
URL = "/";
return temp;
}
std::string temp = URL.substr(0, pos);
URL.erase(0, pos);
return temp;
}
int main(){
using namespace std;
cout << "URL: ";
string url;
cin >> url; // User gibt URL der Datei ein, die herruntergeladen werden soll
#ifndef linux
WSADATA w;
if(int result = WSAStartup(MAKEWORD(2,2), &w) != 0){
cout << "Winsock 2 konnte nicht gestartet werden! Error #" << result << endl;
return 1;
}
#endif
RemoveHttp(url);
string hostname = RemoveHostname(url);
hostent* phe = gethostbyname(hostname.c_str());
if(phe == NULL){
cout << "Host konnte nicht aufgelöst werden!" << endl;
return 1;
}
if(phe->h_addrtype != AF_INET){
cout << "Ungültiger Adresstyp!" << endl;
return 1;
}
if(phe->h_length != 4){
cout << "Ungültiger IP-Typ!" << endl;
return 1;
}
int Socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if(Socket == -1){
cout << "Socket konnte nicht erstellt werden!" << endl;
return 1;
}
sockaddr_in service;
service.sin_family = AF_INET;
service.sin_port = htons(80); // Das HTTP-Protokoll benutzt Port 80
char** p = phe->h_addr_list; // p mit erstem Listenelement initialisieren
int result; // Ergebnis von connect
do{
if(*p == NULL) {
cout << "Verbindung fehlgschlagen!" << endl;
return 1;
}
service.sin_addr.s_addr = *reinterpret_cast<unsigned long*>(*p);
p++;
result = connect(Socket, reinterpret_cast<sockaddr*>(&service), sizeof(service));
}
while(result == -1);
cout << "Verbindung erfolgreich!" << endl;
string request = "GET ";
request += url; // z.B. /faq/index.html
request += " HTTP/1.1\n";
request += "Host: " + hostname + "\nConnection: close\n\n";
try{
SendAll(Socket, request.c_str(), request.size());
int code;
string Protokoll;
stringstream firstLine; // Die erste Linie ist anders aufgebaut als der Rest
do{
GetLine(Socket, firstLine);
firstLine >> Protokoll;
firstLine >> code;
// 100 = Continue
if(code == 100) GetLine(Socket, firstLine); // Leere Zeile nach Continue ignorieren
} while(code == 100);
cout << "Protokoll: " << Protokoll << endl;
if(code != 200){
firstLine.ignore(); // Leerzeichen nach dem Statuscode ignorieren
string msg;
getline(firstLine, msg);
cout << "Error #" << code << " - " << msg << endl;
return 0;
}
bool chunked = false;
const int noSizeGiven = -1;
int size = noSizeGiven;
while(true){
stringstream sstream;
GetLine(Socket, sstream);
if(sstream.str() == "\r") break;// Header zu ende?
string left; // Das was links steht
sstream >> left;
sstream.ignore(); // ignoriert Leerzeichen
if(left == "Content-Length:") sstream >> size;
if(left == "Transfer-Encoding:"){
string transferEncoding;
sstream >> transferEncoding;
chunked = (transferEncoding == "chunked");
}
}
string filename = "download" + GetFileEnding(url);
cout << "Filename: " << filename << endl;
fstream fout(filename.c_str(), ios::binary | ios::out);
if(!fout){
cout << "Could not create file!" << endl;
return 1;
}
int recvSize = 0; // Empfangene Bytes insgesamt
char buf[1024];
int bytesRecv = -1; // Empfangene Bytes des letzten recv
if(size != noSizeGiven){ // Wenn die Größe über Content-length gegeben wurde
cout << "0%";
while(recvSize < size){
if((bytesRecv = recv(Socket, buf, sizeof(buf), 0)) <= 0) throw CreateSocketError();
recvSize += bytesRecv;
fout.write(buf, bytesRecv);
cout << "\r" << recvSize * 100 / size << "%" << flush; // Mit \r springen wir an den Anfang der Zeile
}
}else{
if(!chunked){
cout << "Downloading... (Unknown Filesize)" << endl;
while(bytesRecv != 0){ // Wenn recv 0 zurück gibt, wurde die Verbindung beendet
if((bytesRecv = recv(Socket, buf, sizeof(buf), 0)) < 0) throw CreateSocketError();
fout.write(buf, bytesRecv);
}
}else{
cout << "Downloading... (Chunked)" << endl;
while(true){
stringstream sstream;
GetLine(Socket, sstream);
int chunkSize = -1;
sstream >> hex >> chunkSize; // Größe des nächsten Parts einlesen
if(chunkSize <= 0) break;
cout << "Downloading Part (" << chunkSize << " Bytes)... " << endl;
recvSize = 0; // Vor jeder Schleife wieder auf 0 setzen
while(recvSize < chunkSize){
int bytesToRecv = chunkSize - recvSize;
if((bytesRecv = recv(Socket, buf, bytesToRecv > sizeof(buf) ? sizeof(buf) : bytesToRecv, 0)) <= 0) throw CreateSocketError();
recvSize += bytesRecv;
fout.write(buf, bytesRecv);
cout << "\r" << recvSize * 100 / chunkSize << "%" << flush;
}
cout << endl;
for(int i = 0; i < 2; ++i){
char temp;
recv(Socket, &temp, 1, 0);
}
}
}
}
cout << endl << "Finished!" << endl;
} catch(exception& e){
cout << endl;
cerr << e.what() << endl;
}
#ifdef linux
close(Socket); // Verbindung beenden
#else
closesocket(Socket); // Windows-Variante
#endif
}

77
src/web4rail.server.py

@ -0,0 +1,77 @@ @@ -0,0 +1,77 @@
#!/bin/bash
import socket,sys,os
from thread import *
class web4rail_server:
system = None
def __init__(self,port):
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print 'Socket created.'
try:
self.socket.bind(('',port))
except socket.error as msg:
print 'Bind failed. Error ('+str(msg[0])+'): '+str(msg[1])
sys.exit(-1)
print 'Bound to socket at port '+str(port)
def client(self,conn):
if self.system == None:
self.select_system(conn)
conn.close
def create_system(self,path):
print 'creating new system at '+path
def load_system(self,path):
print 'loading system from '+path
def select_system(self,conn):
path='/'
conn.send("Welcome to the Web2Rail server. Please select a SYSTEM first:\n");
while True:
conn.send('current dir: '+path+"\n")
contents = os.listdir(path)
conn.send("select one from\n")
for entry in contents:
conn.send(' '+entry+"\n")
entry = conn.recv(1024).strip()
if entry in contents:
path += entry
if os.path.isfile(path):
break
path += '/'
else:
conn.send(path+entry+' does not exist. Create (yes/no/abort)? ')
input = conn.recv(1024).strip()
if input == 'yes':
path += entry
self.create_system(path)
break
if input == 'abort':
path = None
break
if path == None:
return
self.load_system(path)
def start(self):
self.socket.listen(10)
print 'Server started.'
while True:
conn, add = self.socket.accept()
start_new_thread(self.client,(conn,))
if len(sys.argv) == 2:
port = int(sys.argv[1])
else:
port = 7965
server = web4rail_server(port)
server.start()
Loading…
Cancel
Save