Documente Academic
Documente Profesional
Documente Cultură
9. Curs Socket
9.1. Introducere
Cursul reprezint o introducere n implementarea comunicaiei ntre procese bazat pe socket. Un socket este un punct final al unei comunicaii, un obiect al unei aplicaii prin care aceasta trimite i recepioneaz date. Prin intermediul lui se realizeaz un schimb de date n regim fullduplex. Un socket are un tip, este asociat unui proces i trebuie s aib un nume. n mod curent socketul schimb date doar cu un alt socket aflat n acelai domeniu de comunicaie i care utilizeaz acelai protocol. Exist dou tipuri de socket: stream; datagram. Socket-ul de tip stream suport un flux de date fr limite sub forma unui ir de octei. Se garanteaz transmiterea i recepionarea corect. Acest tip de socket se mai numete connexion oriented. El utilizeaz protocolul TCP/IP. Socket-ul de tip datagram suport un flux de date orientat spre fiiere. El nu garanteaz livrarea fiierelor. Acest tip de socket se mai numete message oriented. El utilizeaz protocolul UDP. Arhitectura client-server este cea mai potrivit pentru realizarea comunicaiilor bazate pe socket. 9.1.1. Utilizarea firelor pentru evitarea blocrii conexiunii Dac aplicaia client nu are altceva de fcut dect s atepte date atunci nu este necesar s se creeze fire. Dac aplicaia trebuie s rspund i altor evenimente generate de interfaa utilizator, ceea ce este cel mai probabil este necesar s se creeze fire separate pentru citire i scriere. 9.1.2. Despre endianism i transferul datelor Atunci cnd se creeaz o aplicaie pe o anumit platform un programator nu acord mare atenie reprezentrii datelor. Atunci cnd se creeaz o aplicaie pentru reea problema reprezentrii datelor este foarte important. Internetul, n special, a impus o secven standard pentru stocarea datelor numerice referit prin sintagma network byte-order. Spre deosebire, secvena pentru reprezentarea datelor pe calculatorul gazd se numete host byte-order . Aa cum se cunoate, pentru a transmite date de la un sistem la altul, stratul fizic al reelei va transmite un ir de octei prin intermediul firelor de conexiune. Stratul fizic nu modifica secvena de bii pe care o transmite. Dac se transmite numrul 0x1ADE de pe un calculator PC pe un calculator McIntosh, PC-ul, utiliznd little-endian byte-order, va transmite mai nti octetul cel mai puin semnificativ i apoi octetul cel mai semnificativ. La recepie se utilizeaz big-endian byte-order i primul octet va fi interpretat ca octetul cel mai semnificativ. Deci pe Mcintosh numrul trimis de PC va fi interpretat ca 0xDE1A. Pentru a evita asfel de erori Internet-ul definete ca standard de reea big-endian byte-order. Cu alte cuvinte este impus stocarea datelor cu octetul cel mai semnificativ naintea octetului mai puin semnificativ. nainte de a transmite date pe reea este necesar s se fac o transformare a acestora n ordinea big-endian. La recepia datelor de pe reea trebuie s se fac transformarea n ordinea impus de
1
Cap. 9. Socket
platforma pe care se lucreaz. Winsock API ofer o serie de funcii care realizeaz operaiile de transformare a ordinii octeilor. Aceste funcii sunt prezentate n tab. 1.
Tabelul 1. Funcii de conversie Winsock
Explicaii Convertete un intreg pe 32 de bii din hostbyte order n network-byte oreder Convertete un intreg pe 16 de bii din hostbyte order n network-byte oreder Convertete un intreg pe 32 de bii networkbyte oreder din n host- byte order Convertete un intreg pe 16 de bii networkbyte oreder din n host- byte order
9.1.3. Gsirea adresei IP a unui calculator Programele de comunicaie pentru reea trebuie s cunoasc portul pe care aplicaia client poate comunica cu aplicaia server i adresa IP a calculatorului cu care se dorete comunicarea. Pentru gsirea adresei IP este necesar s se utilizeze funcii asincrone pe care Socket API le are sau s se completeze o structur de date specific cu datele de identificare a adresei IP a serverului.
Parametri: Numele
wVersionRequested lpwsaData
Tipul
Word pointer
Descrierea Reprezint versiunea cea mai mare a Winsock API pe care aplicaia o va utiliza. Pointer ctre o structur care va recepiona detalii ale implementrii WinSock. Cod de eroare. Vezi documentaia CVI
Valoare returnat:
status integer
Cap. 9. Socket
Not:
Tipul
int int
Descrierea WinSock1.1 suport doar parametrul AF_INET. Specific tipul de socket. Exist doar dou tipuri de socket suportate de Windows Sockets 1.1: SOCK_STREAM i SOCK_DGRAM. Handle pentru obiect
Valoare returnat:
socket SOCKET
Protocolul nu este precizat n mod explicit deoarece combinaia address family i type, descrie n mod unic protocolul. De exemplu, dac address family este AF_INET i type este SOCK_STREAM, protocolul este TCP, iar dac address family este AF_INET i type este SOCK_DGRAM, protocolul este UDP. La succes funcia ntoarce un descriptor de socket, altfel o valoare INVALID_SOCKET este ntoars i prin apelul unei funcii WSAGetLastError() se pot obine informaii suplimentare asupra tipului de eroare. Printre erorile posibile enumerm: WSANOTINITIALIZED, care apare dac funcia WSAStartup() nu s-a apelat cu succes, WSAENETDOWN, care apare dac reeaua nu este n funciune etc. Urmtorul fragment de cod arat o implementare tipic:
4
SOCKET listenSocket; listenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(listenSocket==INVALID_SOCKET) { MessagePopup ("Eroare", "Eroare la socket()"); closesocket(listenSocket); return 1; }
Parametri: Numele
s addr namelen
Tipul
SOCKET pointer int
Descrierea Descriptorul de socket Pointer ctre o structur sockaddr cu adresa sau numele care va fi atribuit socketului. Numele atribuit socketului
Not:
Dac funcia a avut succes aceasta ntoarce 0, iar n caz contrar ntoarce SOCKET_ERROR. Prin apelul unei funcii WSAGetLastError() se pot obine informaii suplimentare asupra tipului de eroare.
Formatul lui sa_data depinde de address family. n cazul WinSock 1.1, doar adresarea de tip Internet este permis. Din acest motiv o structur socksddr_in este definit. Aceasta va fi utilizat n locul lui sockaddr atunci cnd se apeleaz funcia bind(). Forma acestei structuri este urmtoarea:
struct sockaddr_in { short u_short struct in-addr char }
// // // //
sin_family trebuie s fie AF_INET. Valoarea sin_port trebuie dat n network byte-order. Valoarea sin_addr poate fi dat n trei forme diferite: ca patru octei, ca doi short sau ca un long.
5
Cap. 9. Socket
SOCKADDR_IN saServer; int nPort, nRet; . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . // Construirea structurii numelui saServer.sin_family=AF_INET; saServer.sin_addr.s_addr=INADDR_ANY;//Adresa este pusa de WINSOCK nPort=1200; saServer.sin_port=htons(nPort); // Numarul portului // Asocierea de un port nRet=bind(listenSocket, (LPSOCKADDR) &saServer, sizeof(struct sockaddr)); if(nRet==SOCKET_ERROR) { MessagePopup ("Eroare", "Eroare la bind()"); closesocket(listenSocket); return 1; }
ASCULTAREA UNEI CONEXIUNI Etapa urmtoare este de a pune n ascultare socketul creat n ateptarea unei conexiuni de la clieni. Acest lucru se face cu funcia listen(). Prototipul aceste funcii este:
int listen(SOCKET s, int backlog);
Parametri: Numele
s backlog
Tipul
SOCKET int
Not:
Dac funcia a avut succes aceasta ntoarce 0, iar n caz contrar ntoarce SOCKET_ERROR. Prin apelul unei funcii WSAGetLastError() se pot obine informaii suplimentare asupra tipului de eroare.
// Seteaza socketul sa asculte nRet = listen(listenSocket, SOMAXCONN); if (nRet == SOCKET_ERROR) { MessagePopup ("Eroare", "Eroare la listen()"); closesocket(listenSocket); return 2; }
ACCEPTAREA UNEI CONEXIUNI Urmtoarea operaie este acceptarea unei conexiuni de la client. Funcia accept() realizeaz acest lucru. Prototipul aceste funcii este:
SOCKET accept(SOCKET s, struct socksddr FAR *addr, int FAR *addrlen)
Parametri: Numele
s addr
Tipul
SOCKET pointer
Descrierea Descriptorul de socket Pointer la o structur sockaddr, n care se recepioneaz adresa clientului conectat. Se poate transfera un parametru NULL Lungimea structurii addr. Dac s-a transferat addr ca un pointer NULL atunci i addrlen trebuie s fie nul.
addrlen
int
Not:
Dac funcia a avut succes aceasta ntoarce 0, iar n caz contrar ntoarce SOCKET_ERROR. Prin apelul unei funcii WSAGetLastError() se pot obine informaii suplimentare asupra tipului de eroare.
Acest mod de acceptare a unei conexiuni realizeaz blocarea aplicaiei server pn la apariia unei cereri de conectare de la un client. Exist i o alt modalitate de conectare, fr blocare, prin funcia WSAAsyncSelect(), pe care nu o discutm aici, deoarece implementarea ei n LabWindows/CVI este destul de greoaie.
Cap. 9. Socket
Parametri: Numele
s name
Tipul
SOCKET pointer
Descrierea Descriptorul de socket Pointer la o structur sockaddr, n care se completeaz adresa serverului la care se va conecta clientul; Lungimea structurii sockaddr.
namelen
int
n cadrul acestui fragment de cod s-a presupus c nPort i structura saServer s-au preluat din dou controale ale aplicaiei, unul numeric i unul de tip STRING, iar completarea structurii s-a realizat utiliznd funcia htons(), de care am mai vorbit i strtok(), care este documentat n LabWindows/CVI. Adresa serverului va fi completat n control sub forma clasic, adic cu punct ntre octeii adresei.
Parametri: Numele
s
8
Tipul
SOCKET
Pointer ctre o structur n care se introduc datele de transmis; Lungimea buferului de date; Specific modul de transmitere.
Not:
Dac funcia a avut succes aceasta ntoarce numrul de octei transmii, iar n caz contrar ntoarce SOCKET_ERROR. Prin apelul unei funcii WSAGetLastError() se pot obine informaii suplimentare asupra tipului de eroare.
Recepionarea datelor n cadrul aplicaiilor client-server bazate pe socket se face utiliznd funcia recv(). Aceast funcie are urmtorul prototip:
int recv(SOCKET s,const struct FAR * buff,int len, int flags);
Parametri: Numele
s buff len flags
Tipul
SOCKET pointer int int
Descrierea Descriptorul de socket Pointer ctre o structur n care se introduc datele de transmise; Lungimea buferului de date; Specific modul de recepie.
Not:
Dac funcia a avut succes aceasta ntoarce numrul de octei recepionai iar n caz contrar ntoarce SOCKET_ERROR. Prin apelul unei funcii WSAGetLastError() se pot obine informaii suplimentare asupra tipului de eroare.
Cap. 9. Socket
La crearea unor aplicaii client-server n care serverul se blocheaz la accept(), este indicat ca transmiterea s se fac sub controlul unui buton, iar recepia s se fac n cadrul unui fir la fiecare aplicaie. Exemplu Se vor crea dou aplicaii:
aplicaia server, care s aib interfaa prezentat n fig. 9.2. Aplicaia va realiza sub controlul unor butoane distincte operaiile de creare a unui socket, legare (bind), ascultare (listen). La apsarea butonului accept serverul se va bloca n rutina accept(). Ieirea din aceasta are loc numai dup ce un client se va conecta la server. Atunci se va crea un fir de recepie a datelor de la client. Interfaa utilizator conine controale de tip TEXT BOX i LISTBOX n care vor apare evenimente, informaia care urmeaz s fie transmis i respectiv informaiile transmise ntre client i server. Dac apare o cerere de conexiune de la un client se va aprinde un led pe interfaa utilizator. Butoanele se vor valida sau invalida pentru a permite realizarea unei succesiuni corecte a operaiilor necesare. La apsarea butonului bind va trebui precizat portul pe care se leag serverul.
10
aplicaia client, care s aib interfaa prezentat n fig. 9.3. Aplicaia va realiza sub controlul unor butoane distincte operaiile de creare a unui socket i conectare la server. Adresa serverului i portul trebuie precizate prin completarea controalelor corespunztoare ale interfeei. Codul programului pentru server este urmtorul:
#include #include #include #include #include #include <cvirte.h> <userint.h> "server_socket.h" <winsock2.h> <windows.h> <formatio.h>
static int panelHandle, panel1, panel2; static DWORD dwThreadID; static HANDLE hThread; SOCKET listenSocket; WSADATA m_wsaData; WORD wVersionRequested = MAKEWORD(1,1); SOCKADDR_IN saServer; int nPort, nLineTextRec=0, nLineTextSend=0; char szBuffRecv[256], szBuffSend[256]; static DWORD dwThreadID; static HANDLE hThread; SOCKET remoteSocket; char mes[256]; int nIndex=0, nItem1=0, nItem=0; DWORD WINAPI Thread(LPVOID data);
11
Cap. 9. Socket
int main (int argc, char *argv[]) { if(InitCVIRTE (0, argv, 0) == 0) return -1; /* out of memory */ if((panelHandle = LoadPanel (0,"server_socket.uir",PANEL))< 0) return -1; DisplayPanel (panelHandle); SetCtrlVal(panelHandle, PANEL_LED, 0); RunUserInterface (); DiscardPanel (panelHandle); WSACleanup(); return 0; } int CVICALLBACK Main_Win (int panel, int event, void *callbackData, int eventData1, int eventData2) { switch (event) { case EVENT_CLOSE: TerminateThread(hThread, 0); closesocket(listenSocket); closesocket(remoteSocket); QuitUserInterface (0); break; } return 0; } int CVICALLBACK Creare (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { int nRet; switch (event) { case EVENT_COMMIT: nRet = WSAStartup(wVersionRequested, &m_wsaData); if (m_wsaData.wVersion != wVersionRequested) MessagePopup ("Eroare", "Versiune necorespunzatoare "); listenSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); if(listenSocket==INVALID_SOCKET) { MessagePopup ("Eroare", "Eroare la socket()"); closesocket(listenSocket); return 1; } SetCtrlVal(panelHandle, PANEL_TEXTBOX, "S-a creat un socket pentru legatura cu clientii\n"); SetCtrlAttribute(panelHandle, PANEL_C3, ATTR_DIMMED, 0); SetCtrlAttribute(panelHandle, PANEL_C1, ATTR_DIMMED, 1); SetCtrlAttribute(panelHandle, PANEL_C2, ATTR_DIMMED, 0); break; } return 0; } int CVICALLBACK Af_Info (int panel, int control, int event,
12
void *callbackData, int eventData1, int eventData2) char stri[40]; switch (event) { case EVENT_COMMIT: panel1 = LoadPanel (panelHandle, "server_socket.uir, PANEL1); InstallPopup (panel1); Fmt (stri, "%d.%d", (int)HIBYTE(m_wsaData.wVersion), (int)LOBYTE(m_wsaData.wVersion)); SetCtrlVal(panel1, PANEL1_STRING, stri); SetCtrlVal(panel1, PANEL1_STRING1, m_wsaData.szDescription); SetCtrlVal (panel1, PANEL1_STRING2, m_wsaData.szSystemStatus); Fmt (stri, "%s<%d", m_wsaData.iMaxSockets); SetCtrlVal (panel1, PANEL1_STRING3, stri); Fmt (stri, "%s<%d", m_wsaData.iMaxUdpDg); SetCtrlVal (panel1, PANEL1_STRING4, stri); break; } return 0;
int CVICALLBACK Panel1_Main(int panel, int event, void *callbackData, int eventData1, int eventData2) { switch (event) { case EVENT_CLOSE: RemovePopup (0); break; } return 0; } int CVICALLBACK binds (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { switch (event) { case EVENT_COMMIT: panel2 = LoadPanel (panelHandle, "server_socket.uir", PANEL2); InstallPopup (panel2); SetCtrlAttribute(panelHandle, PANEL_C4, ATTR_DIMMED, 0); SetCtrlAttribute(panelHandle, PANEL_C3, ATTR_DIMMED, 1); break; } return 0; } int CVICALLBACK bind2 (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { int nRet; char stri[20];
13
Cap. 9. Socket
switch (event) { case EVENT_COMMIT: // Construirea structurii numelui saServer.sin_family=AF_INET; saServer.sin_addr.s_addr=INADDR_ANY; // Adresa este pusa de WINSOCK GetCtrlVal(panel2, PANEL2_NUMERIC, &nPort); saServer.sin_port=htons(nPort); // Numarul portului // Asocierea de un port nRet=bind(listenSocket, (LPSOCKADDR) &saServer, sizeof(struct sockaddr)); if(nRet==SOCKET_ERROR) { MessagePopup ("Eroare", "Eroare la bind()"); closesocket(listenSocket); return 1; } RemovePopup (0); SetCtrlVal(panelHandle, PANEL_TEXTBOX, "Serverul"); SetCtrlVal(panelHandle, PANEL_TEXTBOX, " asteapta legatura cu clientii pe portul "); Fmt (stri, "%d", nPort); SetCtrlVal(panelHandle, PANEL_TEXTBOX, stri); SetCtrlVal(panelHandle, PANEL_TEXTBOX, "\n"); break; } return 0;
int CVICALLBACK listen1 (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { int nRet; switch (event) { case EVENT_COMMIT: // Seteaza socketul sa asculte nRet = listen(listenSocket, SOMAXCONN); if (nRet == SOCKET_ERROR) { MessagePopup ("Eroare", "Eroare la listen()"); closesocket(listenSocket); return 2; } SetCtrlVal(panelHandle, PANEL_TEXTBOX, "Serverul este setat sa asculte conexiuni de la clienti\n"); SetCtrlAttribute(panelHandle, PANEL_C5, ATTR_DIMMED, 0); SetCtrlAttribute(panelHandle, PANEL_C4, ATTR_DIMMED, 1); break; } return 0; } int CVICALLBACK accept1 (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) {
14
switch (event) { case EVENT_COMMIT: // Asteptarea unei cereri SetCtrlVal(panelHandle, PANEL_TEXTBOX, "Serverul blocat la accept asteptand conexiuni de la clienti\n"); // Socketul asteptat remoteSocket = accept(listenSocket, NULL, NULL); if (remoteSocket == INVALID_SOCKET) { MessagePopup ("Eroare", "Eroare la accept()"); closesocket(listenSocket); return 4; } SetCtrlVal(panelHandle, PANEL_LED, 1); SetCtrlVal(panelHandle, PANEL_TEXTBOX, "S-a creat firul de receptie al clientului\n"); hThread=CreateThread(NULL,0,Thread,NULL,0,&dwThreadID); break; } return 0; } int CVICALLBACK send1 (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { int nRet; char mes[256]="Server: "; switch (event) { case EVENT_COMMIT: // -------------------------------------------------------------memset(szBuffSend, 0, sizeof(szBuffSend)); GetCtrlVal(panelHandle, PANEL_TEXTBOX1, szBuffSend); strcat (mes, szBuffSend); // mesaj de afisat InsertListItem(panelHandle, PANEL_LISTBOX,nItem,mes,0); GetCtrlAttribute (panelHandle, PANEL_LISTBOX, ATTR_CTRL_INDEX, &nItem); SetCtrlAttribute (panelHandle, PANEL_LISTBOX, ATTR_HILITE_CURRENT_ITEM, 1); CheckListItem (panelHandle, PANEL_LISTBOX, nItem, 1); DeleteTextBoxLines (panelHandle, PANEL_TEXTBOX1, 0, -1); SetActiveCtrl (panelHandle, PANEL_TEXTBOX1); // --------------------------------------------------------------nRet =send(remoteSocket,szBuffSend,strlen(szBuffSend), 0); if (nRet == SOCKET_ERROR) { MessagePopup ("Eroare", "Eroare la send()"); closesocket(remoteSocket); return 5; } SetCtrlVal (panelHandle, PANEL_TEXTBOX, "S-a tansmis un mesaj catre soketul client\n"); break; } return 0;
15
Cap. 9. Socket
} DWORD WINAPI Thread(LPVOID data) { int nRet; while(1) { char mes[256]= "Client: "; memset(szBuffRecv, 0, sizeof(szBuffRecv)); nRet = recv(remoteSocket,szBuffRecv, sizeof(szBuffRecv),0); if (nRet == INVALID_SOCKET) { SetCtrlVal(panelHandle, PANEL_LED, 0); closesocket(listenSocket); closesocket(remoteSocket); return 5; } // -----------------------------------------------------------// Afiseaza datele receptionate strcat (mes, szBuffRecv); InsertListItem(panelHandle,PANEL_LISTBOX nItem, mes, 0); GetCtrlAttribute (panelHandle, PANEL_LISTBOX, ATTR_CTRL_INDEX, &nItem); SetCtrlAttribute (panelHandle, PANEL_LISTBOX, ATTR_HILITE_CURRENT_ITEM, 1); CheckListItem (panelHandle, PANEL_LISTBOX, nItem, 1); SetCtrlVal (panelHandle, PANEL_TEXTBOX, "S-a primit un mesaj de la soketul client\n"); } }
static int panelHandle, panel1, panel2; static DWORD dwThreadID; static HANDLE hThread; SOCKET ClientSocket; WSADATA m_wsaData; WORD wVersionRequested = MAKEWORD(1,1); SOCKADDR_IN saClient; char szBuf[256], szBuf1[256]; int nLineText=0; char mes[256]; int nItem=0; DWORD WINAPI Thread(LPVOID data); int main (int argc, char *argv[]) {
16
if (InitCVIRTE (0, argv, 0) == 0) return -1; /* out of memory */ if ((panelHandle = LoadPanel(0,"client_socket.uir",PANEL))<0) return -1; DisplayPanel (panelHandle); RunUserInterface (); DiscardPanel (panelHandle); WSACleanup(); return 0;
int CVICALLBACK Main_Win (int panel, int event, void *callbackData, int eventData1, int eventData2) { switch (event) { case EVENT_CLOSE: TerminateThread(hThread, 0); closesocket(ClientSocket); QuitUserInterface (0); break; } return 0; } int CVICALLBACK Socket1 (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { int nRet; switch (event) { case EVENT_COMMIT: // Crearea unui socket client nRet = WSAStartup(wVersionRequested, &m_wsaData); if (m_wsaData.wVersion != wVersionRequested) MessagePopup ("Eroare", "Versiune necorespunzatoare "); ClientSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); if(ClientSocket==INVALID_SOCKET) { MessagePopup ("Eroare", "Eroare la socket()()"); closesocket(ClientSocket); return 1; } SetCtrlVal(panelHandle, PANEL_TEXTBOX, "S-a creat un socket client\n"); break; } return 0; } int CVICALLBACK Connect1 (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { unsigned int nPort; int nRet; char cPort_Adr[14]; char *a; switch (event) { case EVENT_COMMIT:
17
Cap. 9. Socket
// Copletarea structurii saClient saClient.sin_family = AF_INET; GetCtrlVal(panelHandle, PANEL_NUMERIC, &nPort); saClient.sin_port=htons(nPort); GetCtrlVal(panelHandle, PANEL_STRING, cPort_Adr); a=strtok(cPort_Adr, "."); saClient.sin_addr.S_un.S_un_b.s_b1=(unsigned char)atoi(a); a=strtok(NULL, "."); saClient.sin_addr.S_un.S_un_b.s_b2=(unsigned char)atoi(a); a=strtok(NULL, "."); aClient.sin_addr.S_un.S_un_b.s_b3=(unsigned char)atoi(a); a=strtok(NULL, "."); saClient.sin_addr.S_un.S_un_b.s_b4=(unsigned char)atoi(a); nRet = connect(ClientSocket,(LPSOCKADDR)&saClient, sizeof(struct sockaddr)); if (nRet == SOCKET_ERROR) { MessagePopup ("Eroare", "Eroare la connect()"); closesocket(ClientSocket); return 2; } SetCtrlVal(panelHandle, PANEL_TEXTBOX, "Clientul este conectat la serverul ales\n"); hThread=CreateThread(NULL, 0, Thread, NULL, 0, &dwThreadID); SetCtrlVal(panelHandle, PANEL_TEXTBOX, "S-a creat firul de receptie al serverului\n"); break; } return 0; } int CVICALLBACK Transmite (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) { int nRet; char mes[256]="Client: "; switch (event) { case EVENT_COMMIT: memset(szBuf1, 0, sizeof(szBuf1)); // mesaj de transmis GetCtrlVal(panelHandle, PANEL_TEXTBOX1, szBuf1); strcat (mes, szBuf1); // mesaj de afisat InsertListItem(panelHandle,PANEL_LISTBOX,nItem, mes, 0); GetCtrlAttribute (panelHandle, PANEL_LISTBOX, ATTR_CTRL_INDEX, &nItem); SetCtrlAttribute (panelHandle, PANEL_LISTBOX, ATTR_HILITE_CURRENT_ITEM, 1); CheckListItem (panelHandle, PANEL_LISTBOX, nItem, 1); DeleteTextBoxLines (panelHandle, PANEL_TEXTBOX1, 0, -1); nRet = send(ClientSocket, szBuf1, strlen(szBuf1), 0); if (nRet == SOCKET_ERROR) { MessagePopup ("Eroare", "Eroare la send()"); closesocket(ClientSocket); return 5; } SetActiveCtrl (panelHandle, PANEL_TEXTBOX1);
18
SetCtrlVal (panelHandle, PANEL_TEXTBOX, "S-a trimis un mesaj catre server\n"); break; } return 0; } DWORD WINAPI Thread(LPVOID data) { int nRet; while(1) { char mes[256]="Server: "; memset(szBuf, 0, sizeof(szBuf)); nRet = recv(ClientSocket, szBuf, sizeof(szBuf), 0); if (nRet == SOCKET_ERROR) { MessagePopup ("Eroare", "Eroare la recv()"); closesocket(ClientSocket); return 3; } strcat (mes, szBuf); InsertListItem(panelHandle,PANEL_LISTBOX,nItem, mes, 0); GetCtrlAttribute (panelHandle, PANEL_LISTBOX, ATTR_CTRL_INDEX, &nItem); SetCtrlAttribute (panelHandle, PANEL_LISTBOX, ATTR_HILITE_CURRENT_ITEM, 1); CheckListItem (panelHandle, PANEL_LISTBOX, nItem, 1); SetCtrlVal (panelHandle, PANEL_TEXTBOX, "S-a primit un mesaj de la server\n"); } }
19