tag:blogger.com,1999:blog-73631987249281157782024-03-13T23:41:48.464-07:00Hovi's blogKarel Hovorkahttp://www.blogger.com/profile/13556888077082214730noreply@blogger.comBlogger3125tag:blogger.com,1999:blog-7363198724928115778.post-40026174849080165722013-12-28T05:24:00.002-08:002014-09-26T04:18:31.724-07:00Detekce hudebních akordů regulárním výrazem
<p>V posledních několika měsících jsem programoval aplikaci pro zobrazování písniček včetně akordů. Akordy byly buď označeny zvláštní značkou (například v závorkách) nebo jen jako součást textu a mým úkolem bylo akord rozeznat pro potenciální transpozici. Transpozice je posunutí všech tónů v písničce o stejný interval. Tím způsobem se pro písničku změní tónina. Pro to je potřeba napřed každý akord správně detekovat a všechny jeho části.</p>
<h2>Struktura zápisu akordu</h2>
<p>Akordy se zapisůjí různě a pro jeden akord existuje často mnoho zápisů. Následující odkazy obsahují možný výčet akordů:</p>
http://www.supermusic.sk/akordy.php
http://www.akordytexty.cz/
<p>Ze zápisů jsem vybral několik akordů:</p>
Cmi6add9
Cmimaj7
C7maj3/A
<p>Není ani tak nutné vědět co akord znamená, ale poznat co je akord a co obsahuje za tón (tóny).</p>
<p>Z příkladů akordů jsem rozdělil akord na několik částí - Tón akordu (C) + modifikace (mi6add9, mimaj7, 7maj3) + / + 2. tón akordu (A)</p>
<h3>Tón akordu</h3>
<p>Tón akordu je písmeno, které reprezentuje tón. Písmeno může následovat ještě posunutí (béčko, křížek, dvojté béčko, dvojitý křížek). Tón akordu může být písmeno A-H. Křížek - zvednutí i půltón se reprezentuje znakem sharp (#), béčko se reprezentuje zpravidla malým b, případně příponou "es" (u tónů A a E je to jen přípona "s"). V českém zápise po tónu A následuje tón H a jeho snížení o půltón je B, neexistuje snížený tón "Hes". V západním zápise neexistuje tón H a nahrazuje ho tón B, jeho snížení je potom Bb. Je tedy faktický půltonový rozdíl mezi západním B a českým B! U dvojitého snížení je to potom přípona "eses", případně "sas" pro A a "ses" pro E. Regulární výraz pro tón je potom následující:</p>
<pre>
[ABCDEFGHabcdefgh](\#|b|ses|sas|es){0,2}
</pre>
<p>Tento výraz má v sobě určitou volnost, protože detekuje i akordy jako třeba "Asassas", detekuje ale všechny možné validní varitanty. Pro přesnější zápis by bylo třeba pro A a E vytvořit výjimky. V případě, že se používá pro zápis jen křížek, béčko a dvojité snížení a zvýšení nehrozí (protože se v praxi na zápis u písniček nezapisují - nemají smysl), regulární výraz se dá zjednodušit na:</p>
<pre>
[ABCDEFGHabcdefgh](\#|b)?
</pre>
<h3>Modifikace akordu</h3>
<p>Modifikace obsahují zpravidla trojpísmenové heslo nebo číslo (1-2 ciferné). Někdy obojí. Některé akordy mají obojí a dvakrát za sebou (mi6add9). Pro pojmutí takové mofikace je nutné mít výčet možných hesel (z odkazů výše) a pak 1-2číslí tyto hesla s číslicemi se mohou opakovat 0-2krát. Regulární výraz pro modifikaci potom vypadá následovně:</p>
<pre>
((maj|mi|sus|add|m)[1-9]{0,2}){0,2}
</pre>
<h3>Druhý tón</h3>
<p>Některé akordy poté ještě obsahují lomítko a další tón. Tento tón má stejná pravidla jako první tón, akorát je následován lomítkem, opět mohou následovat modifikace akordu, i když ne v takovém množství:</p>
<pre>
(\/[ABCDEFGHabcdefgh](\#|b)?)?
</pre>
<h2>Výsledný výraz</h2>
<p>Z předchozích úvah se dá vytvořit složitější nebo jednodušší verze výrazu. Liší se počtem možných zápisů, které výraz přijme, ale také počtem chybných, které výraz přijme. Já osobně používám následující, protože akordy jsou výhradně české, neobsahují dvojité snížení aní zvýšení:</p>
<pre>
([A-Habcdefgh]\#?b?)(?:sus|maj|mimaj|add|aug|dim|min|mi|m|b|\+)?[1-9]{0,2}(?:(\/)
([A-Habcdefgh]\#?b?)(?:sus|maj|mimaj|add|aug|dim|min|mi|m|b|\+)?[1-9]{0,2})?
</pre>
<p>Tento výraz mam rozdělený na několik částí, sestavení v jazyce java vypadá následovně:</p>
<pre>
private static final String SINGLE_TONE = "[A-Habcdefgh]\\#?b?"; // b
private static final String TONE_ADDITIONS = "(?:sus|maj|mimaj|add|aug|dim|min|mi|m|b|\\+)?[1-9]{0,2}";
public static final String FULL_CHORD = "(" + SINGLE_TONE + ")" + TONE_ADDITIONS + "(?:(\\/)(" +
SINGLE_TONE + ")" + TONE_ADDITIONS + ")?";
</pre>
Edit:
<p>Výsledný výraz používám v aplikaci Zpěvník pro android, více o aplikaci na <a href="http://karel-hovorka.eu/zpevnik/">http://karel-hovorka.eu/zpevnik/</a>.</p>Karel Hovorkahttp://www.blogger.com/profile/13556888077082214730noreply@blogger.com1tag:blogger.com,1999:blog-7363198724928115778.post-79031019050015833112012-05-04T10:24:00.000-07:002013-09-20T04:21:21.500-07:00Změna url webu pomocí javascriptu od nerozeznání od webu bez js<h1>Změna url webu pomocí javascriptu od nerozeznání od webu bez js</h1>
<h2>Úvod</h2>
<p>HTML5 umožňuje změnu url v rámci domény. To dříve nešlo a obcházelo se to většinou pomocí url za hashmarkem (#), protože to je část, která se mění jen v rámci stránky, ale neposílá se na server.</p>
<p>
A k čemu to vlastně bude? Touto metodou se stránka může chovat jako by staticky přepínala stránky a přitom bude stránku ovládat javascript a dotahovat stránku na pozadí, samozřejmě s fallbackem pokud prohlížeč nebude pushState podporovat nebo bude mít vyplý javascript. Chování je pro uživatele opticky stejné, ale z programátorského hlediska může být tento způsob výhodnější - žádný refresh.
</p>
<p>
Volání je jednoduché, stačí zavolat metodu pushState objektu history:
</p>
<pre class="sh_javascript">
history.pushState(objekt, nazev, url);
</pre>
<p>
Metoda mimojiné kromě změny url (která je nepovinná) mění "stav" aplikace nastavením aktuálního stavového objektu a jeho názvu. Aktuální stavový objekt je uložen v proměnné
</p>
<pre class="sh_javascript">
history.state
</pre>
<p>
Nám ale bude stačit fukčnost změny url.
Více informací o stavech historie je možné se dočíst ve <a href="http://www.w3.org/TR/html5-author/history.html#session-history-entry">specifikaci</a>
</p>
<h2>Struktura stránky</h2>
<p>
Tady je příklad jak může vypadat stránka, u které chceme použít navigace:
</p>
<pre class="sh_html">
<!DOCTYPE html>
<html lang="cs">
<head>
<meta charset="utf-8">
<title>titulek</title>
</head>
<body>
<header id="header">
<h1>hlavni nadpis</h1>
</header>
<nav id="nav">
<ul>
<li class="vybrany"><a href="uvod.html">Úvod</a></li>
<li><a href="zivotopis.html">Životopis</a></li>
<li><a href="projekty.html">Projekty</a></li>
<li><a href="dalsi.html">Další záliby</a></li>
</ul>
</nav>
<section id="content">
<h2>Úvod</h2>
<p>Now that there is the Tec-9, a crappy spray gun from South Miami. This gun is advertised as the most popular gun in American crime. Do you believe that shit? It actually says that in the little book that comes with it: the most popular gun in American crime. Like they're actually proud of that shit. </p>
</section>
<footer id="footer">
&copy; 2012 <a href="mailto:#">Karel Hovorka</a>
</footer>
</body>
</html>
</pre>
<h2>Navázání události na kliknutí</h2>
<p>
Kromě samotného javascriptu si pomůžeme knihovnou <a href="http://jquery.com/">jQuery</a>.
Chceme odchytit klik na každý odkaz v elementu #nav, toho docílíme následujícím:
</p>
<pre class="sh_javascript">
$(aSelector).each (function() {
$(this).bind("click", function (e) {
//TODO: klik
});
});
</pre>
<p>
Výkonný kód musí dotáhnout data pomocí zvoleného odkazu a aktualizovat potřebná data je potřeba nějakým způsobem roztřídit, na to zvolíme css selektory - my budeme chtít aktualizovat hlavní nadpis (#header h1), obsah (#content) a titulek (title).</p>
<h2>Ajax a parsování dat</h2>
<p>Parsováná data se napřed zkrátí jen na část uvnitř body a obsah elementu title, aby se zbytečně neimportovali a nespouštěli css nebo skripty (skripty uvnitř elementu body se budou pouštět). Volání ajax requestu a první parsování dat vypadá následovně:
</p>
<pre class="sh_javascript">
var request = $.get(href, function(data) {
data = data.substring(data.indexOf("<body>") + 6, data.lastIndexOf("</body>"));
var title = data.substring(data.indexOf("<title>") + 7, data.lastIndexOf("</title>"));
var bodyDom = $($('<div></div>').append(data));
//TODO: aktualizovat data
window.history.pushState("object" + href, "title" + href, href);
});
</pre>
<h2>Aktualizace dat</h2>
<p>
Po poslední části kódu už je k dispozici DOM obsahu dotáhlého dokumentu a obsah elementu title, teď akorát chybí data aktualizovat:
</p>
<pre class="sh_javascript">
var contentSelectors = ["#header h1", "#content", "title"];
var selector;
for (i = 0; i < contentSelectors.length; i++) {
selector = contentSelectors[i];
if (selector == "title") {
document.title = title;
} else {
$(selector).html($(selector, bodyDom).html());
}
}
</pre>
<h2>Aktualizace odkazů</h2>
<p>
Poslední věc, která se často ještě mění je třída položky seznamu, která je zrovna vybrána, toto se aktualizuje následujícím kódem, který napřed třídu vymaže všem existujícím a následně nastaví aktuálním:
</p>
<pre class="sh_javascript">
var clazz;
$("." + clazz).each (function() {
$(this).removeClass(clazz);
});
$("a[href='" + href + "']").each (function() {
$(this).parent("li").addClass(clazz);
});
</pre>
<p>
Toto jsou snad všechny základní myšlenky. Ještě se musí na začátku zjistit jestli prohlížeč vůbec pushState podporuje a navázat události click jen pokud ano. Pak se také musí kontrolovat, že klik byl levým tlačítkem. Nasazení naostro můžete vidět na <a href="http://karel.hovorka.net">karel.hovorka.net</a>.
</p>
<h2>Výsledný kód</h2>
<p>
Výsledný kód po úpravách a dekompozici:
</p>
<pre class="sh_javascript">
function HTML5Nav(contentSelectors, clazz) {
this.clazz = clazz;
this.contentSelectors = contentSelectors;
}
HTML5Nav.prototype.load = function (aSelector) {
var globalThis = this;
if (window.history.pushState) {
$(aSelector).each (function() {
$(this).bind("click", function (e) {
globalThis._click(e);
});
});
}
}
HTML5Nav.prototype._click = function(e) {
if (e.which == 1) {
var a = $(e.target);
var href = a.attr("href");
this.changePage(href);
e.preventDefault();
}
}
HTML5Nav.prototype.changePage = function(href) {
var globalThis = this;
var request = $.get(href, function(data) {
data = data.substring(data.indexOf("<body>") + 6, data.lastIndexOf("</body>"));
var title = data.substring(data.indexOf("<title>") + 7, data.lastIndexOf("</title>"));
var bodyDom = $($('<div></div>').append(data));
globalThis._ajaxResponse(href, bodyDom, title);
});
}
HTML5Nav.prototype._ajaxResponse = function(href, bodyDom, title) {
var selector;
for (i = 0; i < this.contentSelectors.length; i++) {
selector = this.contentSelectors[i];
if (selector == "title") {
document.title = title;
} else {
$(selector).html($(selector, bodyDom).html());
}
}
window.history.pushState("object" + href, "title" + href, href);
this._setSelection(href, this.clazz);
}
HTML5Nav.prototype._setSelection = function(href) {
var clazz = this.clazz;
$("." + clazz).each (function() {
$(this).removeClass(clazz);
});
$("a[href='" + href + "']").each (function() {
$(this).parent("li").addClass(clazz);
});
}
</pre>
<h2>Příklad volání</h2>
<p>
První parametr jsou selektory elementů, které se mají aktualizovat, druhý parametr je třída, kterou mají mít položky seznamu vybraného odkazu.
Metoda load naváže na odkazy událost kliku, jako parametr bere selektor na odkazy, na které chcem vázat odkazy.
Příklad volání kódu :</p>
<pre class="sh_javascript">
var nav = new HTML5Nav(["#header h1", "#content", "title"], "vybrany");
window.onload = nav.load("#nav a");
</pre>
<h2>Odkazy</h2>
<ul>
<li><a href="http://www.w3.org/TR/html5-author/history.html#session-history-entry">W3C specifikace</a></li>
<li><a href="https://developer.mozilla.org/en/DOM/Manipulating_the_browser_history">https://developer.mozilla.org/en/DOM/Manipulating_the_browser_history</a></li>
<li><a href="http://karel.hovorka.net/">karel.hovorka.net - příklad použití</a></li>
<li><a href="http://jquery.com/">jQuery</a></li>
</ul>Karel Hovorkahttp://www.blogger.com/profile/13556888077082214730noreply@blogger.com0tag:blogger.com,1999:blog-7363198724928115778.post-51705020777897942932011-12-08T10:56:00.000-08:002012-01-06T14:50:19.416-08:00Multiplatformní Sockety a TCP pro Windows a Linux v C/C++<h1>Úvod</h1><p>Programování TCP v C je rozdílné ve Windows a Linuxu. Existují wrappery a různé knihovny, které funkcionalitu sjednocují a zlepšují. Rozdíly jsou ale tak malé, že by mohli být řešeny preprocesorem, které by mělo několik výhod:</p><ul><li>Kód se může psát nativně pro jednu platformu.</li>
<li>Direktivy budou krátké a jednoduché.</li>
<li>Zkompilovaný bude rychlý, protože nebude žádná další režie (wrappery).</li>
</ul><h1>Hlavičkové soubory</h1><p>Každý systém má vlastní sadu hlavičkových souborů, které jsou nutné pro funkcionalitu socketů:</p><h3>Windows</h3><p>Existuje několik možných hlavičkových souborů mimo tento (windows.h, Winsock.h).</p><pre class="sh_c">#include <WinSock2.h>
</pre><h3>Linux</h3><pre class="sh_c">#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h></pre><h1>Porovnání funkcí</h1><p>Porovnával jsem následující funkce:</p><br />
<ul><li>socket</li>
<li>bind</li>
<li>listen</li>
<li>accept</li>
<li>send</li>
<li>recv</li>
<li>close (closesocket)</li>
</ul><br />
<h1>Funkce socket</h1><h2>Definice</h2><h3>Windows</h3><pre class="sh_c">SOCKET socket(int af, int type, int protocol);
</pre><h3>Linux</h3><pre class="sh_c">int socket(int domain, int type, int protocol);
</pre><h2>Parametry</h2><p>Parametry jsou stejného datového typu.</p><h2>Návratová hodnota</h2><p>Z definice funkce se zdá, že jediným rozdílem je návratová hodnota, která je ve Windows typu SOCKET a linuxu typu int.<br />
Ve winsock.h je SOCKET definován takto:<br />
</p><pre class="sh_c">typedef u_int SOCKET;</pre>A u_int následně takto:<br />
<pre class="sh_c">typedef unsigned int u_int;</pre>Je to tedy unsigned int a int.<br />
<br />
Úspěch:<br />
V případě úspěchu funkce vrací kladné číslo vyjadřující deskriptor daného socketu pro oba operační systémy.<br />
Chybový stav:<br />
<h3>Windows</h3>Vrací konstantu INVALID_SOCKET, která je definována:<br />
<pre class="sh_c">#define INVALID_SOCKET (SOCKET)(~0)</pre><h3>Linux</h3>Vrací -1, což je binární vyjádření hodnoty ~0<br />
<h1>Funkce bind</h1><h2>Definice</h2><h3>Windows</h3><pre class="sh_c">int bind(SOCKET s, const struct sockaddr *name, int namelen);</pre><h3>Linux</h3><pre class="sh_c">int bind(int s, struct sockaddr *my_addr, socklen_t addrlen);</pre><h2>Parametry</h2><p>První parametr je rozdílný - SOCKET vs int. Rozdíly byly popsány u návratové hodnoty funkce socket.<br />
V linuxu je třetí parametr typu socklen_t, ve windows je to int. Parametr obsahuje velikost truktury sockaddr* druhého parametru. Pokud ho získáme pomocí funkce sizeof("2. parametr"), v linuxu se vrátí datový typ kompatibilní s socketlen_t (nenašel jsem přesnou dokumentaci) a program se bez problémů zkompiluje.<br />
</p><h2>Návratová hodnota</h2>Návratová hodnota je 0 v případě úspěchu. V případě neúspěchu je v linuxu vrácena hodnota -1 a ve windows konstanta SOCKET_ERROR, která je taky -1.<br />
<br />
<h1>Funkce listen</h1><h2>Definice</h2><h3>Windows</h3><pre class="sh_c">int listen(SOCKET s, int backlog);</pre><h3>Linux</h3><pre class="sh_c">int listen(int s, int backlog);</pre><h2>Parametry</h2><p>Podobně jako u funkce bind je zde rozdílný datový typ pro socket.</p><h1>Funkce accept</h1><h2>Definice</h2><h3>Windows</h3><pre class="sh_c">SOCKET accept(SOCKET s, struct sockaddr *addr, int *addrlen); </pre><h3>Linux</h3><pre class="sh_c">int accept(int s, struct sockaddr *addr, socklen_t *address_len);</pre><h2>Parametry</h2><p>Podobně jako u funkce bind je zde rozdílný datový typ pro socket. Další parametry jsou stejné jako u funkce bind s tím rozdílem, že tentokrát se posílají pointery.<br />
Zde může nastat problém, protože některé překladače v linuxu nepovolí třetí parametr typu int bez explicitního přetypování (g++).<br />
</p><h2>Návratová hodnota</h2><p>Stejně jako u funkce socket.</p><br />
<h1>Funkce send</h1><h2>Definice</h2><h3>Windows</h3><pre class="sh_c">int send(SOCKET s, const char *buf, int len, int flags);</pre><h3>Linux</h3><pre class="sh_c">int send(int s, const void *buf, size_t len, int flags); </pre><h2>Parametry</h2><p>Stejný problém s datovým typem socketu a datovým typem pro velikost (size_t vs int).</p><h2>Návratová hodnota</h2><h3>Windows</h3><p>Počet odeslaných bytů, případně SOCKET_ERROR (-1) pokud nastala chyba.</p><h3>Linux</h3><p>Počet odeslaných bytů, případně -1.</p><br />
<h1>Funkce recv</h1><h2>Definice</h2><h3>Windows</h3><pre class="sh_c">int recv(SOCKET s, char *buf, int len, int flags);</pre><h3>Linux</h3><pre class="sh_c">int recv(int s, void *buf, size_t len, int flags);</pre><h2>Parametry</h2><p>Stejný problém s datovým typem socketu a datovým typem pro velikost (size_t vs int).</p><h2>Návratová hodnota</h2><p>Počet přijatých bytů, případně SOCKET_ERROR (-1) pokud nastala chyba. 0 pokud byl socket ukončen standardně.</p><br />
<h1>Funkce close</h1><h2>Definice</h2>Tady je problém přímo v definici - názvy nesouhlasí.<br />
<h3>Windows</h3><pre>int closesocket(SOCKET s);</pre><h3>Linux</h3><pre>int close(int fd);</pre><h2>Parametry</h2><p>Stejný problém s datovým typem socketu.</p><h2>Návratová hodnota</h2><p>0 v případě úspěchu, SOCKET_ERROR (-1) pokud nastala chyba.</p><h1>Windows - specifické funkce</h1>Ve windows se navíc používají funkce na inicializaci a ukončení používání socketů, mezi základní patří funkce:<br />
<pre class="sh_c">WORD MAKEWORD(BYTE bLow, BYTE bHigh); (makro)
int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData);
int WSACleanup(void);
struktura WSADATA (LPWSADATA)</pre>Toto je jen nejzákladnější výčet, funkcí existuje víc. Tyto funkce jsou platformně velmi specifické, ale v jednoduchých případech není potřeba udělat nic víc než startup a cleanup.<br />
<h1>Řešení</h1><p>Mým snažením je udělat řešení tak, aby se dala aplikace psát nativně pro jednu platformu a pomocí makra byla funkční i v druhé platformě. Protože na windows je nutné používat WSA funkce, rozhodl jsem se tuto platformu použít jako nativní.</p><h2>Odstranění problémů s WSA funkcemi</h2><p>V linuxu není nutné tyto funkce volat, proto stačí jen vytvořit funkce s prázdným tělem vracející defaultní hodnoty, případně návratové hodnoty úspěchu.</p><h2>Odstranění rozdílných datových typů pro socket</h2><p>Protože nativní platformou je Windows, nejjednodušším způsobem je dodefinováním datového typu SOCKET.</p><h2>Odstranění problému s socklen_t*</h2><p>Pomocí makra přejmenujeme veškeré výskyty funkce accept na funkci acceptSocket, která bude vnitřně volat funkci accept s explicitním přetypováním na socklen_t*</p><h2>Vytvoření konstant</h2><p>V linuxu nejsou standartně konstanty SOCKET_ERROR a INVALID_SOCKET, stačí je přidat z winsock.h</p><h1>Zdrojový kód</h1><h2>networking.h</h2><pre class="sh_c">#pragma once
#ifdef __unix__ /* __unix__ is usually defined by compilers targeting Unix systems */
//g++
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#define closesocket(socket) close(socket)
typedef int SOCKET;
typedef unsigned short WORD;
#define INVALID_SOCKET (SOCKET)(~0)
#define SOCKET_ERROR (-1)
struct WSADATA {
int x;
};
WORD MAKEWORD(int a, int b);
int WSAStartup(int a, WSADATA* b);
int WSACleanup();
#define accept(socket,addr,addrlen) acceptSocket(socket,addr,addrlen)
int acceptSocket(int s, struct sockaddr *addr, int* addrlen);
#elif defined _WIN32 /* _Win32 is usually defined by compilers targeting 32 or 64 bit Windows systems */
//WIN
#include <WinSock2.h>
#endif</pre><h2>networking.cpp</h2><pre class="sh_cpp">#include "networking.h"
#ifdef __unix__
//g++
WORD MAKEWORD(int a, int b) {
return 0;
}
int WSAStartup(int a, WSADATA* b) {
return 0;
}
int WSACleanup() {
return 0;
}
#define acceptSocket(socket,addr,addrlen) accept(socket,addr,addrlen)
int acceptSocket(int s, struct sockaddr *addr, int* addrlen) {
return accept(s, addr, (socklen_t*) addrlen);
}
#define accept(socket,addr,addrlen) acceptSocket(socket,addr,addrlen)
#endif</pre><h1>Závěr</h1><p>Výše uvedený hlavičkový soubor umožňuje mým C++ projektům ve Visual Studiu 2010 zkompilovatelost v linuxu pomocí g++ bez nutnosti provádění změn. Jsem céčkař začátečník a tak nevím jestli neexistuje podobné lepší řešení (žádné jsem nenašel). Některé věci by určitě šli udělat líp a věrohodněji (aby WSA api opravdu něco dělalo, např. vracelo chybové kódy).</p><h1>Zdroje</h1><a href="http://en.wikipedia.org/wiki/C_preprocessor">http://en.wikipedia.org/wiki/C_preprocessor</a><br />
<a href="http://www.allegro.cc/forums/thread/370013/370226#target">http://www.allegro.cc/forums/thread/370013/370226#target</a><br />
<a href="http://tangentsoft.net/wskfaq/articles/bsd-compatibility.html">http://tangentsoft.net/wskfaq/articles/bsd-compatibility.html</a><br />
<a href="http://www.builder.cz/art/cpp/tcp_server_linux.html">http://www.builder.cz/art/cpp/tcp_server_linux.html</a><br />
<a href="http://www.builder.cz/art/cpp/tcp_server_windows.html">http://www.builder.cz/art/cpp/tcp_server_windows.html</a><br />
<a href="http://research.microsoft.com/en-us/um/redmond/projects/invisible/include/winsock.h.htm">http://research.microsoft.com/en-us/um/redmond/projects/invisible/include/winsock.h.htm</a><br />
<a href="http://pubs.opengroup.org/onlinepubs/7908799/xns/syssocket.h.html">http://pubs.opengroup.org/onlinepubs/7908799/xns/syssocket.h.html</a>Karel Hovorkahttp://www.blogger.com/profile/13556888077082214730noreply@blogger.com0