Permalänk

Trådar i C, Win32 IRC Client

Jag håller på att programmera en IRC client i C till projektarbetet jag håller på med i skolan, varvid jag har stött på problem.

Mina kodkunskaper är fruktansvärt rostiga tyvär, och jag har inte tid med att riktigt sjunka mig ner i tunga kodexempel då tiden är knapp.

Problemet är att programmet för att kunna fungera någorlunda bra, behöver ta emot data från irc-servern, kunna ta in data från användaren och behöver kunna skicka användardata till ircservern. Eftersom det här är processer som troligtvis behöver ske samtidigt så ser trådar som enda lösningen.

Detta visar flödet som jag vill åstakomma:

Server(in) Server(ut) \ / \ / Klient / \ / \ STDIN STDOUT

Så som jag ser det så skulle två trådar räcka bra. En tråd för Server IO och en för användar IO.

Först och främst så är exempel på trådar i C med WinAPI guld värda, ni behöver inte flexxa era kunskaper så om det är simpelt så är det en fördel. Och om ni har andra tips så är de varmt mottagna. Tack i förväg.

Visa signatur

Asus Maximus II formula, E8400 @ 3.9GHz, 4GB Dominator DDR2, Radeon HD4850.

Permalänk
Medlem

För en klient behöver du inte använda trådar.
Att saker sker "samtidigt" innebär att de inte blockerar varandra.

En huvudloop skulle kunna se ut så här:

while running
{
hämta data från servern
presentera datan
hämta data från användaren
skicka eventuellt data till servern
}

om du vill tråda så kan du kika på t.ex.
http://msdn.microsoft.com/en-us/library/ms682516(VS.85).aspx
eller
http://www.codeproject.com/KB/threads/crtmultithreading.aspx

lycka till

Visa signatur

weeeee

Permalänk
Medlem
Citat:

Ursprungligen inskrivet av mounte
while running
{
hämta data från servern
presentera datan
hämta data från användaren
skicka eventuellt data till servern
}

Nyckeln här är att när man hämtar från servern och användaren så ska man bara hämta om det finns något, inte vänta på input. Det betyder att du bör använda non-blocking IO.

Permalänk
Medlem

Självklart så är det som You skriver. Om hämta data från servern tar tid, dvs processen väntar på att det ska bli klart så kommer efterföljande rader inte exekveras föräns data hämtats.

Hittade några sockets-exempel på:
http://www.win32developer.com/tutorial.shtm
som jag använt mig av tidigare.

Visa signatur

weeeee

Permalänk

Problemet med trådar och allt det där är numera löst och visade sig faktiskt vara rätt enkelt. Jag kommar posta all källkod här sen när jag blir klar så någon kanske har nytta för det i framtiden.

Problemet jag har nu är med utmatning i konsolen.

Jag har en linjär array som innehåller alla tecken som blivit upptagna från irc-servern: CHAR_INFO x[80*50].

Där konsolbufferten är 80*50 d.v.s. utrymmet där alla tecken blir skrivna.
Så elementet 80*2 i arrayen motsvarar början på andra raden på skärmen.

Det här är bra och fint så länge all input kommer på en gång till arrayen.

Men när fallet inte längre är så blir det problem. Eftersom då kommer den nya inputen skriva över den gamla i början av arrayen. T.ex. efter all serverinfo blivit lagrad i arrayen och visats på skärmen, och någon användare skickar en rad på 80 tecken till mig. Då kommer första raden på skärmen visa medelandet och skriver över det som fanns där förut.

Jag vill att det ska funka som vilken annan irc-client som hellst. D.v.s jag vill att allt nytt som skrivs till skärmen hamnar på sista raden och allt som finns ovanför den nya raden hoppar upp ett steg med det som fanns längst uppe hoppar ut ur arrayen helt och således även skärmen.

Hur åstakommerjag det här, och har ni uppfattat mig korrekt?

Funktionen i fråga ser ut såhär:

void cConsol::addText(char msg[80*50], int len, bool shift) { int i,x=0,y=0; if(shift){moveText();}// kan ni bortse ifrån, försök till lösning av problemet med någon alghoritm jag försökte skapa som inte löste problemet. for(i=0;i<len;i++) { x++; if(msg[i] != 13 && msg[i] != 10) { cChar[x+80*y].Char.AsciiChar=(int)(msg[i]); cChar[x+80*y].Attributes=225; }else if(msg[i] == 10 || msg[i] == 13) {y++; x=0;} if(i>0 && (i % 80)==0){ y++; x=0;} } //memset(cChar,31,sizeof(cChar)); }

Och ja det ser säkerligen horribelt ut för er erfarna kodare

Snälla fråga om ni vill veta något eller behöver mer kod att kolla på.

Visa signatur

Asus Maximus II formula, E8400 @ 3.9GHz, 4GB Dominator DDR2, Radeon HD4850.

Permalänk
Medlem

Vet inte riktigt om din metod verkligen är den bästa, men för att "flytta upp" alla rader ett steg kan du göra nåt i den här stilen:

void shiftText(char* text, int textlen, int textwidth){ for(int i=0;i<(textlen-textwidth);i++){ *(text+i) = *(text+i+texwidth); // Typ text[ i ] = text[ i+textwidth ] } } (...) shiftText(&msg, 80*50, 80);

Otestad kod.

Sen kan du ju skriva över de sista 80 tecknen (som är sista raden).

Edit: Var är det du kodar egentligen? Det här är inte C nånstans:

cChar[x+80*y].Char.AsciiChar=(int)(msg[i]); cChar[x+80*y].Attributes=225;

Permalänk
Citat:

Ursprungligen inskrivet av mounte
För en klient behöver du inte använda trådar.
Att saker sker "samtidigt" innebär att de inte blockerar varandra.

En huvudloop skulle kunna se ut så här:

while running
{
hämta data från servern
presentera datan
hämta data från användaren
skicka eventuellt data till servern
}

om du vill tråda så kan du kika på t.ex.
http://msdn.microsoft.com/en-us/library/ms682516(VS.85).aspx
eller
http://www.codeproject.com/KB/threads/crtmultithreading.aspx

lycka till

Blir inte detta lite som en busy wait (om man har non blocking IO)?

Ett sätt att lösa det vore att lägga in en select först i for loopen. Tyvärr funkar det väll inte att köra select på stdin i windows så man får väll i så fall försöka med typ WaitForMultipleObjects.

Eller så kan man bara tråda det istället

Permalänk

Ironiskt nog så var den första lösningen jag gjorde till problemet den som faktiskt funkade.

void cConsol::moveText() { int lx,ly; for(ly=0;ly<24;ly++) { for(lx=0;lx<80;lx++) { cChar[lx+80*ly].Char.AsciiChar = cChar[lx+80*(ly+1)].Char.AsciiChar; cChar[lx+80*ly].Attributes=225; if (ly==23) cChar[lx+80*(ly+1)].Char.AsciiChar =' '; } } }

void cConsol::addText(char msg[80*25], int len, bool shift) { int x,y; y=22-(len/80); x=0; if (shift==true) moveText(); for (int l=0;l<(len-1);l++,x++) { if (msg[l]!= 13 && msg[l]) cChar[x+80*y].Char.AsciiChar=msg[l],cChar[x+80*y].Attributes=225; if(msg[l]== 13) {moveText();x=0;}; if(x > 0 && (x % 80 == 0)){x=0;y++;} } }

Sådär ser det ut och verkar funka bra, behövs lite småfixar bara.

You: Gick över från C till C++ halvägs i projektet om det var det du tänkte.

Visa signatur

Asus Maximus II formula, E8400 @ 3.9GHz, 4GB Dominator DDR2, Radeon HD4850.