Sunteți pe pagina 1din 12

Laborator 4

Data Transmission 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. send() and WSASend() WSASendDisconnect() Out-of-Band Data recv() and WSARecv() WSARecvDisconnect() Stream Protocols Scatter-Gather I/O Breaking the Connection shutdown() closesocket() TCP Receiver/Server With select() Example

Data Transmission
Trimiterea i primirea datelor este obiectivul principal al programarii in retea. Pentru a trimite date pe un socket conectat, exist dou funcii API: send () i WSASend ().A doua funcie este specifica pentru Winsock 2. De asemenea, dou funcii sunt pentru primirea de date pe un socket conectat: recv () i WSARecv (). Acesta din urm este, de asemenea, un apel Winsock 2. Un lucru important de reinut este faptul c toate tampoanele asociate cu trimiterea i primirea de date sunt de tip char care este doar byte simplu orientate spre date. n realitate, ea poate fi un tampon cu orice date brute in el, fie c e vorba de date binare sau de stringuri nu conteaz. n plus, codul de eroare returnat de ctre funciile send() si receive() este SOCKET_ERROR. Odat ce se returneaz o eroare, apelam WSAGetLastError () pentru a obine informaii extinse despre eroare. Dou dintre cele mai frecvente erori ntlnite sunt WSAECONNABORTED i WSAECONNRESET. Ambele au legatura cu inchiderea conexiunii , fie printr-un timp de expirare sau prin nchiderea conexiunii decatre client. O alt eroare frecvent este WSAEWOULDBLOCK, care este n mod normal, ntlnita atunci cnd, socluri nonblocking sau asincrone sunt folosite. Aceast eroare nseamn n esen c funcia specificat nu poate fi finalizata n acest moment.
172.16.11.201

send() and WSASend()


Prima funcia API pentru a trimite date pe un socket conectat este : int send( SOCKET s, const char FAR * buf, int len,

int flags ); Parametrul SOCKET este folosit pentru a trimite datele .Al doilea parametru, buf, este un indicator de tampon de caractere care conine datele care urmeaz s fie trimise. Al treilea parametru, len, precizeaz numrul de caractere n zona-tampon ce vor fi transmise . n cele din urm, flag e un parametru care poate fi 0, MSG_DONTROUTE, sau MSG_OOB. MSG_DONTROUTE specifica ruta de transport pentru pachetele trimise. MSG_OOB semnific faptul c datele ar trebui s fie trimise urgent. Send returneaz numrul de octei trimis, n caz contrar, n cazul n care apare o eroare, SOCKET_ERROR va fi returnata. O eroare comun este WSAECO-NNABORTED, care apare atunci cand cade un circuit virtual din cauza unei erori de expirare sau de protocol. Atunci cnd se ntmpl acest lucru, socket-ar trebui s fie nchise, deoarece nu mai este utilizabil. WSAECONNRESET se produce atunci cnd cererea de pe gazda de la distan reiniializeaz un circuit virtual prin execuia unui reset hard sau se ncheie n mod neateptat, sau atunci cnd gazda de la distan este repornit. Din nou, socket-ar trebui s fie nchis dup ce aceast eroare se produce. Uultima eroare comun este WSAETIMEDOUT, care apare atunci cnd conexiunea este czuta din cauza unei erori de reea a sistemului aflat la distanta . Functia WSASend (), este definita astfel: int WSASend( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesSent, DWORD dwFlags, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine ); Socket este un descriptor valabil la o sesiune de conectare.Al doilea parametru este un indicator la una sau mai multe structuri WSABUF. Acest lucru poate fi fie o structur unic sau o serie de astfel de structuri. Al treilea parametru indic numrul de structuri WSABUF ce trebuie transmise. Amintii-v c fiecare structur de WSABUF este un tampon . Am putea s ne ntrebm de ce-ar vrea sa trimita mai mult de un tampon de la un moment dat. Aceasta tehnica se numete scatter-gather I/O . LpNumberOfBytesSent este un pointer la o valoare DWORD care ntoarce la un apel WSASend () contine numrul total de octei trimis. DwFlags e un parametru echivalent cu omologul su din send(). Ultimii doi parametri, lpOverlapped i lpCompletionRoutine, sunt utilizati pentru overlapped I / O. WSASend () seteaza lpNumberOfBytesSent la numrul de octei trimisi. Funcia returneaz 0 n cazul succesului i SOCKET_ERROR . WSASendDisconnect() int WSASendDisconnect(SOCKET s, LPWSABUF lpOutboundDisconnectData); Out-of-Band Data Atunci cnd o cerere pe un socket flux conectat are nevoie pentru a trimite date mai importante dect datele din flux, se pot marca datele importante ca out-of-band . Aplicatia de la cellalt capt al conexiunii poate primi i prelucra datele cu caracter OBD printr-un canal separat logic, care este conceptual independent de fluxul de date. In TCP, datele ODB sunt puse n aplicare prin intermediul unui bit 1 numit URG .

recv() and WSARecv() int recv( SOCKET s, char FAR* buf, int len, int flags ); Primul parametru, S, este soclul pe care datele vor fi primite.Al doilea parametru, buf, este un tampon de caractere care va primi date, len este fie numrul de octei pe care dorii s-i primii sau mrimea tampon , buf. Stream Protocols

S presupunem c avei un tampon cu 2,048 octei de date pe care dorii s le trimitei cu funciasend(). Codul pentru a trimite acest lucru este: char sendbuff[2048]; int nBytes = 2048; // Fill sendbuff with 2048 bytes of data // Assume s is a valid, connected stream socket ret = send(s, sendbuff, nBytes, 0);

E posibil ca send() sa nu trimita toti cei 2048 de octeti datorita umplerii bufferelor sau datorita modificarii feresteri de receptie prin mecanismul terestrei glisante.Pentru a fi siguri ca trimitem toate caracterele din buffer putem folosi codul : char sendbuff[2048]; int nBytes = 2048, nLeft, idx; // Fill sendbuff with 2048 bytes of data nLeft = nBytes; idx = 0; while (nLeft > 0) { // Assume s is a valid, connected stream socket ret = send(s, &sendbuff[idx], nLeft, 0); if (ret == SOCKET_ERROR) { // Error handler } nLeft -= ret; idx += ret; } Breaking the Connection Odat ce ai terminat cu o conexiune, trebuie s nchidei soclul i sa eliberati orice resurse asociate cu descriptorul de socket . Pentru a elibera de fapt, resursele asociate cu un soclu deschis,se utilizeaz closesocket () . shutdown() int shutdown(SOCKET s, int how); Parametrul how poate fi SD_RECEIVE, SD_SEND, or SD_BOTH.

Value SD_SEND (0) SD_RECEIVE (1) SD_BOTH (2)

Meaning Shutdown send operations. Shutdown receive operations. Shutdown both send and receive operations.

closesocket()
int closesocket (SOCKET s);

TCP Receiver/Server

#include <winsock2.h> #include <stdio.h> // A sample of the select() return value int recvTimeOutTCP(SOCKET socket, long sec, long usec) { // Setup timeval variable struct timeval timeout; struct fd_set fds; // assign the second and microsecond variables timeout.tv_sec = sec; timeout.tv_usec = usec; // Setup fd_set structure FD_ZERO(&fds); FD_SET(socket, &fds); // Possible return values: // -1: error occurred // 0: timed out // > 0: data ready to be read return select(0, &fds, 0, 0, &timeout); }

int main(int argc, char **argv) { WSADATA wsaData; SOCKET ListeningSocket, NewConnection; SOCKADDR_IN ServerAddr, SenderInfo; int Port = 7171; // Receiving part char recvbuff[1024]; int ByteReceived, i, nlen, SelectTiming; // Initialize Winsock version 2.2 if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) { // The WSAGetLastError() function is one of the only functions // in the Winsock 2.2 DLL that can be called in the case of a WSAStartup failure printf("Server: WSAStartup failed with error %ld.\n", WSAGetLastError()); // Exit with error return 1; } else { printf("Server: The Winsock DLL found!\n"); printf("Server: The current status is %s.\n", wsaData.szSystemStatus); } if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2 ) { //Tell the user that we could not find a usable WinSock DLL printf("Server: The dll do not support the Winsock version %u.%u!\n", LOBYTE(wsaData.wVersion),HIBYTE(wsaData.wVersion)); // Do the clean up WSACleanup(); // and exit with error return 1; } else { printf("Server: The dll supports the Winsock version %u.%u!\n", LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion)); printf("Server: The highest version this dll can support is

%u.%u\n", LOBYTE(wsaData.wHighVersion), HIBYTE(wsaData.wHighVersion)); } // Create a new socket to listen for client connections. ListeningSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // Check for errors to ensure that the socket is a valid socket. if (ListeningSocket == INVALID_SOCKET) { printf("Server: Error at socket(), error code: %ld.\n", WSAGetLastError()); // Clean up WSACleanup(); // and exit with error return 1; } else printf("Server: socket() is OK!\n"); // Set up a SOCKADDR_IN structure that will tell bind that we // want to listen for connections on all interfaces using port 7171. // The IPv4 family ServerAddr.sin_family = AF_INET; // host-to-network byte order ServerAddr.sin_port = htons(Port); // Listen on all interface, host-to-network byte order ServerAddr.sin_addr.s_addr = htonl(INADDR_ANY); // Associate the address information with the socket using bind. // Call the bind function, passing the created socket and the sockaddr_in // structure as parameters. Check for general errors. if (bind(ListeningSocket, (SOCKADDR *)&ServerAddr, sizeof(ServerAddr)) == SOCKET_ERROR) { printf("Server: bind() failed! Error code: %ld.\n", WSAGetLastError()); // Close the socket closesocket(ListeningSocket); // Do the clean up WSACleanup(); // and exit with error return 1;

} else printf("Server: bind() is OK!\n"); // Listen for client connections with a backlog of 5 if (listen(ListeningSocket, 5) == SOCKET_ERROR) { printf("Server: listen(): Error listening on socket %ld.\n", WSAGetLastError()); // Close the socket closesocket(ListeningSocket); // Do the clean up WSACleanup(); // Exit with error return 1; } else printf("Server: listen() is OK, I'm listening for connections...\n"); // Set 10 seconds 10 useconds timeout SelectTiming = recvTimeOutTCP(ListeningSocket, 10, 10); switch (SelectTiming) { case 0: // Timed out, do whatever you want to handle this situation printf("\nServer: Timeout lor while waiting you retard client!...\n"); break; case -1: // Error occurred, more tweaking here and the recvTimeOutTCP()... printf("\nServer: Some error encountered with code number: %ld\n", WSAGetLastError()); break; default: { // Accept a new connection when available. 'while' always true while(1) { // Reset the NewConnection socket to SOCKET_ERROR // Take note that the NewConnection socket in not listening NewConnection = SOCKET_ERROR; // While the NewConnection socket equal to SOCKET_ERROR

// which is always true in this case... while(NewConnection == SOCKET_ERROR) { // Accept connection on the ListeningSocket socket and assign // it to the NewConnection socket, let the ListeningSocket // do the listening for more connection NewConnection = accept(ListeningSocket, NULL, NULL); printf("\nServer: accept() is OK...\n"); printf("Server: New client got connected, ready to receive and send data...\n"); // At this point you can do two things with these sockets // 1. Wait for more connections by calling accept again // on ListeningSocket (loop) // 2. Start sending or receiving data on NewConnection. ByteReceived = recv(NewConnection, recvbuff, sizeof(recvbuff), 0); // When there is data if ( ByteReceived > 0 ) { printf("Server: recv() looks fine....\n"); // Some info on the receiver side... getsockname(ListeningSocket, (SOCKADDR *)&ServerAddr, (int *)sizeof(ServerAddr)); printf("Server: Receiving IP(s) used: %s\n", inet_ntoa(ServerAddr.sin_addr)); printf("Server: Receiving port used: %d\n", htons(ServerAddr.sin_port)); // Some info on the sender side // Allocate the required resources memset(&SenderInfo, 0, sizeof(SenderInfo)); nlen = sizeof(SenderInfo); getpeername(NewConnection, (SOCKADDR *)&SenderInfo, &nlen); printf("Server: Sending IP used: %s\n", inet_ntoa(SenderInfo.sin_addr)); printf("Server: Sending port used: %d\n", htons(SenderInfo.sin_port)); // Print the received bytes. Take note that this is the

total // byte received, it is not the size of the declared buffer printf("Server: Bytes received: %d\n", ByteReceived); // Print what those bytes represent printf("Server: Those bytes are: \""); // Print the string only, discard other // remaining 'rubbish' in the 1024 buffer size for(i=0;i < ByteReceived;i++) printf("%c", recvbuff[i]); printf("\""); } // No data else if ( ByteReceived == 0 ) printf("Server: Connection closed!\n"); // Others else printf("Server: recv() failed with error code: %d\n", WSAGetLastError()); } // Clean up all the send/recv communication, get ready for new one if( shutdown(NewConnection, SD_SEND) != 0) printf("\nServer: Well, there is something wrong with the shutdown(). The error code: %ld\n", WSAGetLastError()); else printf("\nServer: shutdown() looks OK...\n"); // Well, if there is no more connection in 15 seconds, // just exit this listening loop... if( recvTimeOutTCP(ListeningSocket, 15, 0) == 0) break; } } } printf("\nServer: The listening socket is timeout...\n"); // When all the data communication and listening finished, close the socket if(closesocket(ListeningSocket) != 0) printf("Server: Cannot close \"ListeningSocket\" socket. Error code: %ld\n", WSAGetLastError()); else printf("Server: Closing \"ListeningSocket\" socket...\n");

// Finally and optionally, clean up all those WSA setup if(WSACleanup() != 0) printf("Server: WSACleanup() failed! Error code: %ld\n", WSAGetLastError()); else printf("Server: WSACleanup() is OK...\n"); return 0; }

S-ar putea să vă placă și