Hem anat uns dies a Narbona i hem aprofitat per visitar el parc de Sigean. El cert és que ens ho hem passat molt bé. Hem gaudit de la piscina del lloc on hem anat, hem visitat Narbona ciutat i hem pujat al tren turístic que fa la volta per la ciutat.
També hem visitat pobles de la zona, com Peyriac de Mer on hi ha unes salines amb uns camins de fusta per sobre de l'aigua o Gruissan, que té un castell petitet al centre on es pot pujar i està envoltat d'aigua. També hem visitat la platja de Gruissan que és força curiosa per la urbanització que té i per la seva mida immensa.
Pel que fa a Sigean, és algo car, però vam estar tot el dia i és força interessant. Els animals estan en zones molt grans i no és el mateix que un zoo on estan engabiats. Molt recomanable pels nens.
Recentment he tingut que fer un mini-webserver, multithread per tal que faci d'sparring d'una altra aplicació. Algo fàcil de fer servir, ràpid de configurar, i que respongui a les peticions un contingut fàcil de modificar. Així que he fet al Listener. No té suport per SSL, encara que no és difícil afegir-li.
Té un formulari que li fa d'interface d'usuari i dues classes principals.
HttpServer: Aquesta classes es dedica a tenir un Socket que escolta peticions entrants. Per cada petició entrant instancia una HttpProcessor que s'encarrega de servir la petició en el seu propi thread.
HttpProcessor: Aquesta classes s'encarrega d'atendre una petició. La parseja i li serveix el que demana, ja sigui un GET o un POST.
El codi més interessant del HttpServer és:
publicvoid Listen() {
IPAddress localhost = IPAddress.Any;
listener = new TcpListener(localhost, port);
listener.Start();
ThreadPool.SetMaxThreads(NumThreads, NumThreads);
while (is_active) {
if (listener.Pending())
{
TcpClient client = listener.AcceptTcpClient();
HttpProcessor processor = new HttpProcessor(client, this);
ThreadPool.QueueUserWorkItem(processor.process);
}
else
{
Thread.Sleep(100);
}
}
}
El HttpProcessor per la seva banda:
class HttpProcessor : IDisposable
{
public TcpClient socket { get; set; }
public HttpServer server { get; set; }
private BufferedStream inputStream;
private StreamWriter outputStream;
privatebool isDisposing = false;
privatestring http_contenttype { get; set; }
privatestring http_method { get; set; }
privatestring http_url { get; set; }
privatestring http_protocol_versionstring { get; set; }
privateDictionary<string, string> httpHeaders = newDictionary<string, string>();
privateDictionary<string, string> urlParameters = newDictionary<string, string>();
privatestaticint MAX_POST_SIZE = 10 * 1024 * 1024; // 10MBpublicvoid Dispose()
{
if (!isDisposing)
{
isDisposing = true;
if (inputStream != null)
{
inputStream.Dispose();
inputStream = null;
}
if (outputStream != null)
{
if (outputStream.BaseStream != null)
{
try
{
outputStream.Dispose();
}
catch
{
}
}
outputStream = null;
}
if (socket != null)
{
socket.Close();
socket = null;
}
}
}
public HttpProcessor(TcpClient s, HttpServer srv)
{
this.socket = s;
this.server = srv;
}
privatestring streamReadLine(BufferedStream PinputStream)
{
int next_char = 0;
string data = "";
int i = 0;
while (i < 10000 && next_char != -1)
{
next_char = PinputStream.ReadByte();
if (next_char != -1)
{
if (next_char == '\n')
{
break;
}
else
{
if (next_char != '\r')
{
data += Convert.ToChar(next_char);
}
}
}
i++;
}
return data;
}
publicvoid process(Object threadContext)
{
try
{
inputStream = new BufferedStream(socket.GetStream());
outputStream = new StreamWriter(socket.GetStream(), Encoding.Default);
//HttpGetProcessor httpGetProcessor;//HttpPostProcessor httpPostProcessor;
parseRequest();
readHeaders();
server.IFace.SetResultsValue("URL: " + http_url);
server.IFace.SetResultsValue("Method: " + http_method);
server.IFace.SetResultsValue("Headers ---------");
foreach(KeyValuePair<string, string> Item in httpHeaders)
{
server.IFace.SetResultsValue(Item.Key + ": " + Item.Value);
}
switch (http_method)
{
case"GET":
//httpGetProcessor = new HttpGetProcessor
(http_url, httpHeaders, urlParameters, outputStream, server);//httpGetProcessor.ProcessGETRequest();
EscriureResposta();
break;
case"POST":
//Carrega totes les dades del POST//Dictionary<string, string> PostValues = ReadPostContents();//httpPostProcessor = new HttpPostProcessor
(http_url, httpHeaders, urlParameters, outputStream, server, PostValues);//httpPostProcessor.ProcessPOSTRequest();
server.IFace.SetResultsValue("--------------- POST -------------");
server.IFace.SetResultsValue(ReadPostContents());
EscriureResposta();
break;
case"HEAD":
case"PUT":
case"DELETE":
case"TRACE":
case"CONNECT":
server.IFace.SetResultsValue("Verb HTTP no suportat: " + http_method);
break;
case"UNKNOWN":
server.IFace.SetResultsValue("Verb HTTP desconegut: " + http_method);
break;
}
server.IFace.SetResultsValue("CLOSING------");
Dispose();
}
catch (Exception e)
{
server.IFace.SetResultsValue("Exception: " + e.ToString());
Thread.CurrentThread.Join(10000);
}
}
privatevoid EscriureResposta()
{
HttpCodes Codes = new HttpCodes();
string Capcalera = Codes.Success(http_contenttype, "");
string Contingut = server.IFace.GetResponseValue();
Capcalera += Environment.NewLine + "Content-Length: " + Contingut.ToCharArray().Length;
outputStream.Write(Capcalera);
//Aquests writelines separa els headers de la resposta del contigut de la resposta
outputStream.WriteLine("");
outputStream.WriteLine("");
//Envia el contingut
outputStream.Write(Contingut);
outputStream.Flush();
outputStream.Close();
}
privatevoid parseRequest()
{
string request = streamReadLine(inputStream);
request = request.Trim();
if (!string.IsNullOrWhiteSpace(request))
{
string[] tokens = request.Split(' ');
if (tokens.Length != 3)
{
thrownewException("Invalid HTTP request line: ->" + request + "<-");
}
http_method = tokens[0].ToUpper();
http_url = tokens[1];
if (http_url.Contains("?")) parseURLParameters();
http_protocol_versionstring = tokens[2];
}
else
{
http_method = "UNKNOWN";
}
}
privatevoid parseURLParameters()
{
string[] URL = http_url.Split('?');
if(URL.Length != 2)
{
server.IFace.SetResultsValue("ERROR: URL no valida: " + http_url);
}
string[] Parameters = URL[1].Split('&');
string[] Parameter;
http_url = URL[0];
foreach (string item in Parameters)
{
Parameter = item.Split('=');
if(Parameter.Length != 2)
{
server.IFace.SetResultsValue("ERROR: Parametre no valid: " + Parameter);
}
urlParameters.Add(Parameter[0], Parameter[1]);
}
}
privatevoid readHeaders()
{
String line;
while ((line = streamReadLine(inputStream)) != null)
{
line = line.Trim();
if (line.Equals(""))
{
return;
}
int separator = line.IndexOf(':');
if (separator == -1)
{
thrownewException("Invalid HTTP header line: ->" + line + "<-");
}
String name = line.Substring(0, separator);
int pos = separator + 1;
while ((pos < line.Length) && (line[pos] == ' '))
{
pos++; // strip any spaces
}
string value = line.Substring(pos, line.Length - pos);
//Console.WriteLine("header: {0}:{1}",name,value);
httpHeaders.Add(name, value);
}
}
privateconstint BUF_SIZE = 4096;
privatestring ReadPostContents()
{
// this post data processing just reads everything into a memory stream.// this is fine for smallish things, but for large stuff we should really// hand an input stream to the request processor. However, the input stream // we hand him needs to let him see the "end of the stream" at this content // length, because otherwise he won't know when he's seen it all! //Console.WriteLine("get post data start");int content_len = 0;
MemoryStream ms = new MemoryStream();
StreamReader SR = null;
string PostData = "";
//Dictionary<string, string> PostValues;if (httpHeaders.ContainsKey("Content-Length"))
{
content_len = Convert.ToInt32(httpHeaders["Content-Length"]);
if (content_len > MAX_POST_SIZE)
{
thrownewException(String.Format("POST Content-Length({0}) too big for this simple server", content_len));
}
byte[] buf = newbyte[BUF_SIZE];
int to_read = content_len;
while (to_read > 0)
{
//Console.WriteLine("starting Read, to_read={0}",to_read);int numread = this.inputStream.Read(buf, 0, Math.Min(BUF_SIZE, to_read));
//Console.WriteLine("read finished, numread={0}", numread);if (numread == 0)
{
if (to_read == 0)
{
break;
}
else
{
thrownewException("POST Client disconnected during post");
}
}
to_read -= numread;
ms.Write(buf, 0, numread);
}
ms.Seek(0, SeekOrigin.Begin);
}
SR = new StreamReader(ms);
PostData = SR.ReadToEnd();
return PostData;
//PostValues = ProcessPostValues(PostData);//return PostValues;
}
privateDictionary<string, string> ProcessPostValues(string PostData)
{
Dictionary<string, string> PostValues = newDictionary<string, string>();
string EncodedHTTP;
string DecodedString;
string[] Splitter;
string[] ItemSplitter;
Splitter = PostData.Split('&');
for (int i = 0; i < Splitter.Length; i++)
{
ItemSplitter = Splitter[i].Split('=');
if (ItemSplitter.Length == 2)
{
EncodedHTTP = ItemSplitter[1];
DecodedString = WebUtility.UrlDecode(EncodedHTTP);
PostValues.Add(ItemSplitter[0], DecodedString);
}
}
return PostValues;
}
}
També hi ha una classe de support que encapsula els codis HTTP, i el formulari principal fa servir la classe de configuració.
class HttpCodes
{
publicstring SuccessJSON()
{
string Result = "";
Result = "HTTP/1.0 200 OK";
Result += Environment.NewLine + "Content-Type: application/json; charset=iso-8859-1";
Result += Environment.NewLine + "Cache-Control: no-cache, no-store, must-revalidate";
Result += Environment.NewLine + "Pragma: no-cache";
Result += Environment.NewLine + "Expires: 0";
Result += Environment.NewLine + "Connection: close";
return Result;
}
publicstring SuccessHTML()
{
string Result = "";
Result = "HTTP/1.0 200 OK";
Result += Environment.NewLine + "Content-Type: text/html; charset=iso-8859-1";
Result += Environment.NewLine + "Cache-Control: no-cache, no-store, must-revalidate";
Result += Environment.NewLine + "Pragma: no-cache";
Result += Environment.NewLine + "Expires: 0";
Result += Environment.NewLine + "Connection: close";
return Result;
}
/// <summary>/// Resposta amb 200 OK/// </summary>/// <param name="ContentType">application/xml, text/xml, text/html</param>/// <param name="Charset">Valors posibles "iso-8859-1" o "" per no enviar cap</param>/// <returns></returns>publicstring Success(string ContentType, string Charset)
{
string Result = "";
Result = "HTTP/1.0 200 OK";
if(string.IsNullOrWhiteSpace(Charset))
{
Result += Environment.NewLine + "Content-Type: " + ContentType;
}
else
{
Result += Environment.NewLine + "Content-Type: " + ContentType + "; charset=" + Charset;
}
//Result += Environment.NewLine + "Content-Type: " + ContentType + "; charset=iso-8859-1";//Result += Environment.NewLine + "Content-Type: application/xml";//Result += Environment.NewLine + "Content-Type: text/xml";
Result += Environment.NewLine + "Cache-Control: no-cache, no-store, must-revalidate";
Result += Environment.NewLine + "Pragma: no-cache";
Result += Environment.NewLine + "Expires: 0";
Result += Environment.NewLine + "Connection: close";
return Result;
}
publicstring SuccessText()
{
string Result = "";
Result = "HTTP/1.0 200 OK";
Result += Environment.NewLine + "Content-Type: text/plain; charset=iso-8859-1";
Result += Environment.NewLine + "Cache-Control: no-cache, no-store, must-revalidate";
Result += Environment.NewLine + "Pragma: no-cache";
Result += Environment.NewLine + "Expires: 0";
Result += Environment.NewLine + "Connection: close";
return Result;
}
publicstring Error500()
{
string Result = "";
Result = "HTTP/1.0 500 Internal Server Error";
Result += Environment.NewLine + "Content-Type: text/plain; charset=iso-8859-1";
Result += Environment.NewLine + "Cache-Control: no-cache, no-store, must-revalidate";
Result += Environment.NewLine + "Pragma: no-cache";
Result += Environment.NewLine + "Expires: 0";
Result += Environment.NewLine + "Connection: close";
return Result;
}
/// <summary>/// Escriu un 200 OK amb el content type que toca/// </summary>/// <param name="IMG">jpg, gif, png</param>publicstring SuccessIMG(string IMG)
{
string Result = "";
Result = "HTTP/1.0 200 OK";
Result += Environment.NewLine + "Content-Type: image/" + IMG;
Result += Environment.NewLine + "Cache-Control: no-cache, no-store, must-revalidate";
Result += Environment.NewLine + "Pragma: no-cache";
Result += Environment.NewLine + "Expires: 0";
Result += Environment.NewLine + "Connection: close";
return Result;
}
publicstring SuccessCSS()
{
string Result = "";
Result = "HTTP/1.0 200 OK";
Result += Environment.NewLine + "Content-Type: text/css";
Result += Environment.NewLine + "Cache-Control: no-cache, no-store, must-revalidate";
Result += Environment.NewLine + "Pragma: no-cache";
Result += Environment.NewLine + "Expires: 0";
Result += Environment.NewLine + "Connection: close";
return Result;
}
publicstring SuccessJS()
{
string Result = "";
Result = "HTTP/1.0 200 OK";
Result += Environment.NewLine + "Content-Type: application/x-javascript";
Result += Environment.NewLine + "Cache-Control: no-cache, no-store, must-revalidate";
Result += Environment.NewLine + "Pragma: no-cache";
Result += Environment.NewLine + "Expires: 0";
Result += Environment.NewLine + "Connection: close";
return Result;
}
publicstring FileNotFound404()
{
string Result = "";
Result = "HTTP/1.0 404 File not found";
Result += Environment.NewLine + "Content-Type: text/plain";
Result += Environment.NewLine + "Cache-Control: no-cache, no-store, must-revalidate";
Result += Environment.NewLine + "Pragma: no-cache";
Result += Environment.NewLine + "Expires: 0";
Result += Environment.NewLine + "Connection: close";
return Result;
}
publicstring Redirect(string URL)
{
string Result = "";
Result = "HTTP/1.1 302 Found";
Result += Environment.NewLine + "Location: " + URL;
Result += Environment.NewLine + "Connection: close";
return Result;
}
}
El Listener té un germà gran que fa més coses, si algun dia l'acabo ja el publicaré
#31/05/2016 12:30 Programació C# Autor: Alex Canalda
Aquest és el n-Essim llibre del Miles, el 15 crec que he llegit. Almenys aquest no és una novel·la rosa... I igual que el James Bond el Miles cada cop està més atrotinat. I encaixa amb la resta de llibres, impressive!
[Spoilers] En Miles està tornant de lluna de mel i té ja els nens encarregats i al forn (vull dir que estan en un capsa a casa seva creixent) quan rep una missió de l'Emperador. I l'envia a l'estació Graf. Aquella que surt al primer llibre. Allí s'ha muntat un embolic tremendu amb un assassinat pel mig. Resulta que un "ba", un serf de Cetaganda, ha segrestat tot un carregament d'embrions dels nous lords i va liquidant amb una bioarma a tothom que ho esbrina. El Miles resulta infectat però aconsegueix detenir-lo. Un cop detingut l'entrega al cetangadesos per tal d'evitar una guerra amb ells ja que pensen que ha estat Barrayar qui ha segrestat els seus nens. Aquest cop com al final queda KO l'ajuda la Ekaterin (la seva dóna) i el Roic el seu soldat. Acaba amb més defectes al seu cos que quan comença el llibre, cada cop més atrotinat.[/Spoilers]
El llibre m'ha agradat més que els 2 anteriors, té més acció i és menys romàtic.
Quan jo era jove (collons, quina M. escriure això), fa uns 25 anys... Bé el cas és que aquell estiu a la casa del poble no tenia lectura. Però a la casa hi havien llibres ja antics (les primeres edicions de Poldark són del 1945...), i entre els llibres vells estaven dos volums de Poldark. Els vaig llegir aquell estiu, i hem van agradar molt. Donat la meva super memòria els hauria de tornar a llegir, perque he vist que hi ha 12 llibres de Poldark... Però centrem-nos, el cas és que al 2015 la BBC britànica va fer aquesta serie basada en els llibres, 8 capítols d'una hora més o menys. I la BBC no ha retallat en gastos, l'ambientació en l'any 1783 està molt ben aconseguida, la fotografia és molt bona i els paisatges espectaculars (ja només amb això jo estic content). Suposo que tenien enveja de Downton Abbey. Pel public femení hi ha varies escenes on el protagonista llueix tipet, i es que l'home està tremendo: a la platja fent un bany o una segant un camp d'herba és especialment insultant, vull dir que res a envejar.
[Spoilers] L'acció es situa després de que Anglaterra ha perdut la guerra d'independència dels USA (sobre el 1783) i el Ross Poldark torna a casa seva. Quan torna el seu pare és mort i ha deixat un munt de deutes, la seva ex-xicota està promesa amb el seu cosí (i es casa), les seves propietats estan en mal estat... Un panorama fantàstic. A partir d'aquí ell remunta i supera tots els obstacles el millor que pot, coneix a la Demelza i munta un negoci de mineria rentable. I lluita contra els Warleggan que són una família de banquers sense escrúpols.
Dintre del drama, hi ha una malaltia que li mata una filla i gairebé la dóna. També munta una foneria que els banquers porten a la ruïna. Al final el porten a la presó per que els Warleggan pensen que ha assassinat a un cosí trampós dels Warleggan que viatjava en un vaixell que naufraga just davant de casa seva. I així acaba la temporada, en un punt àlgid, i emocionant.[/Spoilers]
Per desgracia fins la tardor del 2016 no surt la següent temporada que tindrà 10 capítols enlloc de 8, i comenten que està planificada una tercera temporada. Can't wait! Molt recomanada!
Aquesta és una mini novel·la rosa, amb un xic, petit, petit d'scifi pel mig. És mini perque la seva extensió és molt curta. Almenys ja que és rosa, és curta. Que sigui curta també va bé perque no avorreix ni t'enganxa durant gaire temps, en una tarda es pot llegir. Suposo que l'autora la va escriure per omplir un fet puntual i que tampoc tenia gaire temps per enrollar-se, potser tenia una data d'entrega o algo.
[Spoilers] La mini novel·la tracta del casament del Miles amb la Ekaterine, penso aquest relat es podria haver posat com un capítol final al llibre anterior, però potser van apretar amb dates d'entrega... Està explicat des del punt de vista del Roic i la Taura. El Roic és un soldat dels Vorkosigan i la Taura és una sargent del Mercenaris Dendarii creada amb enginyeria genètica. S'enrollen i el Miles es casa. Tot super-extra rosa. L'únic que hi ha mini-emocionant intent d'assassinat de la Ekaterin, la núvia, amb un collar de perles que li regalen i la Taura ho detecta. Però res gaire complicat.[/Spoilers]
Recomanable? Pse-pse, a veure es llegeix per que és curt i està en la serie i encaixa en la història general. O bé perque agrada el tema rosa, extra-rosa. Next!
Aquest és el 13 llibre de la serie Vorkosigan que llegeixo, i no és sci-fy. És més aviat una comèdia romàntica, a vegades una mica ñoña.
[Spoilers] El llibre segueix el que ja va començar en Komarr, es a dir com el Miles intenta conquistar a la Ekaterine ara que ambdós estan a Barrayar. El llibre narra les ficades de pota, els estira i arronsa de la relació... Amb el decorat de fons del casament de l'Emperador i un parell de peticions curioses. Acaba en varies bodes. [/Spoilers]
Tot tractat amb to de comèdia, amb molta noblesa, molt Emperador, molts comtes Vor, etc... En algun moment sembla que llegís "Sisi emperatriz". No arriba a avorrir, però tampoc emociona ni entusiasma com altres llibres de la serie encara que té algunes situacions divertides. Si es volen naus i pew-pew en aquest llibres hi ha 0.
OMG 11 temporades... no se a partir de quan es converteix en un culebron. En plan capítol 2.986 i sumant. El cas es que segueix en la mateix dinàmica que l'anterior, és un "más de lo mismo". Qui es lia amb qui, qui es separa, qui es reconcilia, etc...
[Spoilers] L'únic fet rellevant de la serie es que el Derek Sheperd, Mr. doctor macizo, parella de la Grey, mor en un accident de tràfic. Es veu que estaria cansat de la serie i la volia deixar definitivament. El curiós és que amb els "flashbacks" de moments tendres de temporades anteriors es veuen uns personatges molt més joves, clar, han passat 11 anys... Clar jo tenia 31! Un iogurin jo per aquell temps...
Per altra banda el yayet ex-jefe de cirurgia es casa.[/Spoilers]
He llegit que hi ha una temporada 12 i que han renovat la serie per una 13... Encara queda, sembla que no acabarà mai això. En fins seré jo un yayet i encara seguirà...