Skicka binär data via UDP-protokoll (Winsock) Jag gör ett klientprogram som kräver att binär data skickas till servern via UDP-protokollet. (Jag använder winsock kontrollen) Jag har använt följande kod. Dim ByteX som Byte Dim X så länge Dim FileX som Interger Winsock3.LocalPort 10000 Winsock3.RemoteHost 211.233.70.51 Winsock3.RemotePort 9500 FileX FreeFile Öppna App. Path udp1.dat för binär som FileX X 1 Gör till X FileLen (App. Path udp1.dat) 1 Hämta FileX. X, ByteX Winsock3.SendData ByteX X X 1 Loop Stäng FileX När jag skickar data på detta sätt skickar den 52 paket som innehåller 1 byte i stället för 1 paket som innehåller 52 byte. Koden fungerar korrekt för TCP-protokollet, men UDP fungerar inte detsamma. Hur kan jag skicka binär data med UDP-protokollet som bara skickar 1 paket data Jag gör ett klientprogram som kräver att binär data skickas till servern via UDP-protokollet. (Jag använder winsock kontrollen):: Jag har använt följande kod. :: Dim ByteX som Byte: Dim X så länge: Dim FileX som Interger:: Winsock3.LocalPort 10000: Winsock3.RemoteHost 211.233.70.51: Winsock3.RemotePort 9500:: FileX FreeFile: Öppna App. Path udp1.dat för binär som FileX : X 1: Gör till X FileLen (App. Path udp1.dat) 1: Hämta FileX. X, ByteX: Winsock3.SendData ByteX: X X 1: Loop: Stäng FileX:: När jag skickar data på detta sätt skickar den 52 paket som innehåller 1 byte i stället för 1 paket som innehåller 52 byte. Koden fungerar korrekt för TCP-protokollet, men UDP fungerar inte detsamma. Hur kan jag skicka binär data med UDP-protokollet som bara skickar 1 paket data: Hej Försök med denna Winsock3.Protocol sckUDPProtocol Winsock har som standard sckTCPProtocol .. lilaDont ta livet för allvarligt, ändå kommer du inte att flyga levande från det att du använder binär data genom att använda winsock Im ledsen, säger du att jag måste använda Datagram istället för Stream Sockets för att få det här jobbet jag använder SOCKSTREAM just nu, och jag föredrar att stanna kvar med det. Finns det något sätt att få detta för att acceptera 0x00 och acceptera data efter det, samtidigt som den använder strömuttag. Återigen, tack för all din hjälp. Mikyu Hmm, det är konstigt. Jag trodde att SOCKDGRAM-argumentet skulle ange binär data, i motsats till SOCKSTREAM. : Recv bör läsa utöver nollor i det fallet. : Är du säker på att du inte tar in data i en strängdatatyp som du skriver ut eller skriver till en fil eller något med en av str-rutinerna: Jag menar du är säker på att du visar den mottagna dataen korrekt Jag är ledsen, säger du att jag måste använda Datagram istället för Stream Sockets för att ha det här arbetet jag använder SOCKSTREAM just nu, och jag föredrar att stanna kvar med det. Finns det något sätt att få detta för att acceptera 0x00 och acceptera data efter det, samtidigt som den använder strömuttag. Återigen, tack för all din hjälp. : mikyu:. Hmm, det är konstigt. Jag trodde att SOCKDGRAM-argumentet skulle ange binär data, i motsats till SOCKSTREAM. . Recv bör läsa utöver nollor i det fallet. . Är du säker på att du inte tar in data i en strängdatatyp som du skriver ut eller skriver till en fil eller något med en av str-rutinerna. Jag menar, är du säker på att du visar den mottagna data korrekt: SOCKDGRAM betyder inte binär data. Det betyder att du vill använda UDP-protokollet för att skicka data och data skickas i datagram. SOCKSTREAM innebär att du vill använda TCP-protokoll och skicka data som ström. Socket bryr sig inte om vilken typ av data du skickar. Allt du behöver är pekare till buffert som innehåller data och längd för bufferten. Noll inuti data betyder ingenting, det är bara noll. Data avslutas inte med noll då C-strängar är. Socket bryr sig inte om innehållet i data. Jag tror att det är något fel med att du får kod. Kanske använder du noll som terminator där, vilket är väldigt dåligt. Om du skulle kunna posta kod som tar emot data här kan jag försöka ta reda på vad som är fel med det. Här är koden som jag använder. Återigen, jag är ny hos winsock så snälla bära med mig. Tack kod int server (tom) unsigned char recmsg3072 SOCKET serverfd, clientfd lyssna på sockfd, ny anslutning på newfd SOCKADDRIN serveraddr SOCKADDRIN clientaddr int len int j int msgsize 0 char fråga WSADATA wsadata unsigned short verrequest FILMike LINGER LingVar verrequest MAKEWORD (2,2 ) (WSAStartup (verrequest, ampwsadata) -1) printf (kan inte hitta en användbar Winsock DLL) utgång (1) om ((serverfd-uttag (AFINET, SOCKSTREAM, 0)) -1) perror (SERVER SIDE: kan inte öppna uttaget) LingVar. lonoff TRUE LingVar. llinger 0 if (setockopt (serverfd, SOLSOCKET, SOOOBINLINE, (char FAR) ampLingVar, sizeof (LingVar)) -1) perror (SERVER SIDE: kunde inte utföra setsockopt) exit (1) serveraddr. sinfamily AFINET serveraddr. sinport htons (SERVERPORT) serveraddr. sinaddr. saddr htonl (INADDRANY) memset (amp (serveraddr. sinzero), 8) om (bind (serverfd, (struct sockaddr) ampserveraddr, sizeof (serveraddr)) -1) perror SIDE: kan inte binda port) avsluta (1) om (lyssna (serverfd, PACKETQUEUE) -1) per ror (SERVER SIDE: kan inte lyssna på uttaget) avsluta (1) memset (recmsg, 0x0, 3072) medan (1) printf (fråga om) fortsätt (YN)) fråga getchar (fråga N fråga n) returnera 0 printf (SERVER SIDE: Väntar på data på port) len sizeof (clientaddr) clientfd acceptera (serverfd, (struct sockaddr) ampclientaddr, amplen) om (clientfd -1) perror (SERVER SIDE: kan inte acceptera anslutning) returnera ERROR printf (SERVER SIDE: mottagen anslutning från: s, inetntoa (clientaddr. sinaddr)) msgsize readline (recmsg, clientfd, clientaddr) om (msgsize ERROR) printf (SERVER SIDE: kunde inte läsa meddelande) coutltltthis är meddelandestorlek : (lmtmsgsizeltltendl fwrite (recmsg, sizeof (short int), 10, mike) för (j0 jlt10 j) printf (- c, recmsgj) closesocket (clientfd) om (WSACleanup () -1) perror (Problem med WSACLEANUP) 1) Int READ READLINE (unsigned char buf, SOCKET sd, SOCKADDRIN clientaddr) char segMAXDATA int offset 0 int res 1 int cliLen memset (seg, 0x0, MAXDATA) cliL en sizeof (clientaddr) medan (res recvfrom (sd, seg, MAXDATA, 0, (struct sockaddr) ampclientaddr, ampcliLen) SOCKETERROR) om (resEOFresWSAECONNRESETresWSAECONNABORTED) 0other side terminated conn printf (Client terminated connection) return offset memcpy seg, res) offset res memset (seg, 0x0, MAXDATA) returnera ERROR-kod: SOCKDGRAM betyder inte binär data. Det betyder att du vill använda UDP-protokollet för att skicka data och data skickas i datagram. SOCKSTREAM innebär att du vill använda TCP-protokoll och skicka data som ström. :: Socket bryr sig inte om vilken typ av data du skickar. Allt du behöver är pekare till buffert som innehåller data och längd för bufferten. :: Noll inuti data betyder ingenting, det är bara noll. Data avslutas inte med noll då C-strängar är. Socket bryr sig inte om innehållet i data. :: Jag tror att det är något fel med att du får kod. Kanske använder du noll som terminator där, vilket är väldigt dåligt. Om du skulle kunna posta kod som tar emot data här kan jag försöka ta reda på vad som är fel med det. : En introduktion till Windows-socket Programmering med C Vad har vi i det här kapitlet 1 del 4 Datasändning skicka () och WSASend () WSASendDisconnect () Out-of-Band Data recv () och WSARecv () WSARecvDisconnect () Streamprotokoll Scatter - Gather IO Bryt anslutningsavstängningen () clossocket () TCP ReceiverServer Med välj () Exempel Datatransmissionssändning () och WSASend () WSASendDisconnect () Out-of-Band Data recv () och WSARecv () Mottagningsförfrågan kommer endast att slutföras när en av följande händelser inträffar: Bufferten som tillhandahålls av den som ringer är helt full. Anslutningen är stängd. Förfrågan har annullerats eller ett fel inträffade. Observera att om den underliggande transporten inte stöder MSGWAITALL, eller om uttaget är i ett icke-blockerande läge, misslyckas det här samtalet med WSAEOPNOTSUPP. Dessutom, om MSGWAITALL anges tillsammans med MSGOOB, MSGPEEK eller MSGPARTIAL, misslyckas det här samtalet med WSAEOPNOTSUPP. Den här flaggan stöds inte på datagramkontakter eller meddelandeorienterade CO-uttag. Naturligtvis 0 specificerar inga speciella åtgärder. MSGPEEK gör att data som kan kopieras till den medföljande mottagningsbufferten. men denna data tas inte bort från systembufferten. Antalet byte som väntar återkommer också. Meddelandet kikar är dåligt. Det försämrar inte bara prestanda, eftersom du nu måste göra två systemsamtal (en för att titta och en utan MSGPEEK-flaggan för att faktiskt ta bort data), men det är också opålitligt under vissa omständigheter. Data som returneras kanske inte återspeglar hela tillgängligt tillgängligt belopp. Genom att lämna data i systembuffertarna har systemet mindre utrymme för att innehålla inkommande data. Som ett resultat minskar systemet TCP-fönsterstorleken för alla avsändare. Detta förhindrar att din ansökan uppnår maximal möjlig genomströmning. Det bästa är att kopiera all data du kan till din egen buffert och manipulera den där. Det finns vissa överväganden när du använder recv () på ett meddelande - eller datagrambaserat uttag som UDP, som vi kommer att beskriva senare. Om data som väntar är större än den medföljande bufferten, fylls bufferten med så mycket data som det kommer att innehålla. I detta fall genererar recv () samtalet felet WSAEMSGSIZE. Observera att felet i meddelandestorleken uppstår med meddelandeinriktade protokoll. Stream protokoll som TCP buffert inkommande data och kommer att returnera så mycket data som ansökningsförfrågningar, även om mängden av pågående data är större. Således för strömmande protokoll kommer du inte att stöta på WSAEMSGSIZE-felet. Funktionen WSARecv () lägger till några nya funktioner över recv (), såsom överlappade IO och partiella datagrammeddelanden. Definitionen av WSARecv () är: Parameter s är det anslutna uttaget. Den andra och tredje parametern är buffertarna för att ta emot data. Parametern lpBuffers är en uppsättning WSABUF-strukturer, och dwBufferCount indikerar antalet WSABUF-strukturer i arrayen. Parametern lpNumberOfBytesReceived pekar på antalet byte som mottages av det här samtalet om mottagningsoperationen slutförs omedelbart. Parametern lpFlags kan vara ett av värdena MSGPEEK, MSGOOB eller MSGPARTIAL, eller en bitvis ELLER kombination av dessa värden. MSGPARTIAL-flaggan har flera olika betydelser beroende på var den används eller stöter på. För meddelandeorienterade protokoll som stöder partiell meddelanden (som AppleTalk), ställs den här flaggan på retur från WSARecv () (om hela meddelandet inte kunde returneras i det här samtalet på grund av otillräckligt buffertutrymme). I det här fallet anger följande WSARecv () samtal denna flagga tills hela meddelandet returneras när MSGPARTIAL-flaggan raderas. Om denna flagg passeras som en ingångsparameter, måste mottagningsoperationen slutföras så snart data finns tillgängligt, även om det bara är en del av hela meddelandet. MSGPARTIAL-flaggan används endast med meddelandeinriktade protokoll, inte med strömmande. Dessutom stödjer inte alla protokoll partiella meddelanden. Protokollposten för varje protokoll innehåller en flagga som anger om den stöder den här funktionen. LpOverlapped och lpCompletionRoutine parametrar används i överlappade IO-operationer, diskuteras i andra kapitel. Det finns en annan specialiserad mottagningsfunktion som du borde vara medveten om: WSARecvDisconnect (). WSARecvDisconnect () Den här funktionen är motsatsen till WSASendDisconnect () och definieras enligt följande: int WSARecvDisconnect (SOCKET s, LPWSABUF lpInboundDisconnectData) Som dess motsändare är parametrarna för WSASendDisconnect () det anslutna uttaget och en giltig WSABUF-struktur med data som ska tas emot. Den mottagna data kan endast koppla bort data som skickas av en WSASendDisconnect () på den andra sidan kan den inte användas för att ta emot vanliga data. Dessutom, när informationen har tagits emot, avaktiverar den här funktionen mottagningen från fjärrpartiet, vilket motsvarar att kalla funktionen shutdown () som beskrivs senare) med SDRECEIVE. Stream-protokoll Eftersom de flesta anslutningsinriktade kommunikationerna, t ex TCP, är streamingprotokoll, beskriv dem kort här kortfattat. Ett strömmande protokoll är en som avsändaren och mottagaren kan bryta upp eller samla data i mindre eller större grupper. Följande figur beskriver kortfattat flödet av TCP-paket mellan klient - och serverns sidor. Det viktigaste att vara medveten om med någon funktion som skickar eller tar emot data på ett strömuttag är att du inte är garanterad att läsa eller skriva hur mycket data du begär. Låt oss säga att du har en teckenbuffert med 2048 byte data du vill skicka med sändningsfunktionen. Koden för att skicka detta är: int nBytes 2048 Fyll sendbuff med 2048 bytes data Antag att s är en giltig, ansluten strömuttag ret send (s, sendbuff, nBytes, 0) Det är möjligt att skicka för att returnera efter att ha skickat mindre än 2048 byte . Retvariabeln ställs in på antalet byte som skickas eftersom systemet tilldelar en viss mängd buffertutrymme för varje socket för att skicka och ta emot data. Vid sändning av data innehåller de interna buffertarna data som ska skickas fram till dess att data kan placeras på ledningen. Flera vanliga situationer kan orsaka detta. Genom att helt enkelt överföra en stor mängd data kommer dessa buffertar att bli fyllda snabbt. Även för TCPIP finns det vad som kallas fönsterstorleken (glidande fönsterdemo). Mottagningsänden justerar denna fönsterstorlek för att ange hur mycket data den kan ta emot. Om mottagaren översväms med data, kan det ställa in fönsterstorleken till 0 för att komma ikapp med den pågående data. Detta kommer att tvinga avsändaren att stanna tills den tar emot en ny fönsterstorlek större än 0. Vid vårt skickade samtal kan det finnas buffertutrymme som bara rymmer 1024 byte, i vilket fall måste du skicka in de återstående 1024 byte. Följande kod ser till att alla dina byte skickas: int nBytes 2048, nLeft, idx Fyll sendbuff med 2048 byte data medan (nLeft gt 0) Antag att s är ett giltigt anslutet strömuttag Saker blir lite komplicerade om dina meddelandestorier varierar . Det är nödvändigt att införa ditt eget protokoll för att låta mottagaren veta hur stort det kommande meddelandet kommer att bli. Till exempel kommer de första fyra byte som skrivs till mottagaren alltid att vara heltalstorleken i byte av det kommande meddelandet. Mottagaren börjar varje läsning genom att titta på de första fyra bitarna, konvertera dem till ett heltal och bestämma hur många ytterligare byte meddelandet omfattar. Scatter-Collect IO Scatter-gather support är ett koncept som ursprungligen introducerades i Berkeley Sockets med funktionerna recv och writev. Den här funktionen är tillgänglig med Winsock 2-funktionerna WSARecv (), WSARecvFrom (), WSASend () och WSASendTo (). Det är mest användbart för applikationer som skickar och tar emot data som är formaterad på ett mycket specifikt sätt. Exempelvis kan meddelanden från en klient till en server alltid bestå av en fast 32-byte header som anger en viss operation, följt av ett 64-byte datablock och avslutas med en 16-byte trailer. I det här exemplet kan WSASend () kallas med en uppsättning av tre WSABUF-strukturer, var och en motsvarar de tre meddelandetyperna. På mottagaränden kallas WSARecv () med tre WSABUF-strukturer, som var och en innehåller databuffers av 32 byte, 64 byte och 16 byte. Vid användning av strömbaserade uttag behandlar spridningssamlingsoperationer helt enkelt de medföljande databuffertarna i WSABUF-strukturerna som en sammanhängande buffert. Dessutom kan mottagaranropet återvända innan alla buffertar är fulla. På meddelandebaserade uttag mottages varje samtal till en mottagningsoperation ett enda meddelande upp till den medföljande buffertstorleken. Om buffertutrymmet är otillräckligt misslyckas samtalet med WSAEMSGSIZE och data trunkeras för att passa tillgängligt utrymme. Naturligtvis kan MSGPARTIAL-flaggan användas för att förhindra förlust av data med protokoll som stöder partiella meddelanden. Bryta anslutningen När du är färdig med en uttag, måste du stänga den och släppa ut eventuella resurser som är kopplade till det uttaget. För att faktiskt släppa ut resurserna som är kopplade till ett handtag med öppet uttag, använd avslutningsfacket () - samtalet. Observera dock att closesocket () kan ha några negativa effekter, beroende på hur det kallas, vilket kan leda till dataförlust. Av denna anledning bör en anslutning avslutas elegant med funktionen shutdown () innan ett samtal till funktionen clossocket (). Dessa två API-funktioner diskuteras nedan. avstängning () För att säkerställa att alla data som skickas till en ansökan, mottas av juryen, bör en välskriven ansökan meddela mottagaren att ingen ytterligare data ska skickas. På samma sätt bör peer göra detsamma. Detta är känt som en graciös nära och utförs av funktionen shutdown (), definierad som: int shutdown (SOCKET s, int hur) Hur parametern kan vara SDRECEIVE, SDSEND eller SDBOTH. För SDRECEIVE är efterföljande samtal till någon mottagningsfunktion på uttaget inte tillåtna. Detta har ingen effekt på de lägre protokolllagren. Och för TCP-uttag, om data är i kö för mottagning eller om data kommer senare, återställs anslutningen. På UDP-uttag accepteras emellertid fortfarande inkommande data och köas (eftersom avstängning () har ingen betydelse för anslutningsfria protokoll). För SDSEND är efterföljande samtal till någon sändningsfunktion ogiltigförklarad. För TCP-uttag orsakar detta att ett FIN-paket genereras efter att alla data har skickats och bekräftats av mottagaren. Slutligen inaktiverar specificering av SDBOTH både sändningar och mottagningar. Observera att inte alla anslutningsinriktade protokoll stöder graciös stängning, vilket är vad shutdown () API utför. För dessa protokoll (t. ex. ATM), stängs endast lås () måste ringas för att avsluta sessionen. En flagga som beskriver vilka typer av operation som sammanfattas i följande tabell. Möjliga värden för denna flagga anges i Winsock2.h headerfilen. När funktionen shutdown () är aktiverad för att inaktivera skicka, ta emot eller båda, finns det ingen metod att återaktivera skicka eller ta emot för befintlig anslutning. En ansökan bör inte förlita sig på att kunna återanvända ett uttag efter att det har stängts av. I synnerhet är en Windows Sockets-leverantör inte skyldig att stödja användningen av connect () på ett uttag som har stängts av. Om en applikation vill återanvända ett uttag, ska funktionen DisconnectEx () kallas med dwFlags-parametern som inställd på TFREUSESOCKET för att stänga en anslutning på ett uttag och förbereda uttaget för att återanvändas. När begäran om DisconnectEx () avslutas kan sockethandtaget skickas till AcceptEx () eller ConnectEx () - funktionen. Om en applikation vill återanvända ett uttag kan TransmitFile () eller TransmitPackets () - funktionerna ringas med dwFlags-parametervärdet med TFDISCONNECT och TFREUSESOCKET för att koppla ur efter att alla data har lagts i kö för överföring och förbereda uttaget för att återanvändas. När TransmitFile () - förfrågan slutförts kan sockethandtaget skickas till det funktionssamtal som tidigare användes för att upprätta anslutningen, till exempel AcceptEx () eller ConnectEx (). När funktionen TransmitPackets () avslutas kan sockethandtaget skickas till AcceptEx () - funktionen. Observera att uttaget från nätsladden är föremål för den underliggande transportens beteende. Till exempel kan ett TCP-uttag vara föremål för TCP TIMEWAIT-tillståndet, vilket orsakar att DisconnectEx (), TransmitFile () eller TransmitPackets () - samtalet försenas. clossocket () Funktionen closesocket () stänger ett uttag och definieras som: int closesocket (SOCKET s) Om inget fel inträffar stängs kontakten () tillbaka noll. I annat fall returneras ett värde av SOCKETERROR, och en specifik felkod kan hämtas genom att ringa WSAGetLastError (). Stickkontakten är markerad som nonblocking, men lonoff-medlemmen av lingerstrukturen är inställd på icke-noll och lingerelementet i lingerstrukturen är inställd på ett icke-zero timeout-värde. Calling clossocket () släpper ut socketbeskrivaren och eventuella ytterligare samtal med socketfel med WSAENOTSOCK. Om det inte finns några andra referenser till det här uttaget, släpps alla resurser som är associerade med beskrivaren. Detta innefattar att kassera någon ködata. Väntar på synkrona samtal som utfärdas av någon tråd i denna process avbryts utan att någon meddelandemeddelanden skickas. Väntar på överlappade operationer avbryts också. Eventuella händelser, färdigställningsrutiner eller färdigställningsportar som är förknippade med den överlappade operationen utförs men misslyckas med felet WSAOPERATIONABORTED. Dessutom påverkar en annan faktor beteendet hos clossocket (): om socketalternativ SOLINGER har ställts in. En ansökan bör alltid ha ett matchande samtal för att stänga facket () för varje lyckat samtal till socket för att returnera eventuella socket resurser till systemet. TCP ReceiverServer Med välj () Exempel 1. Medan i Visual C IDE, klicka på File meny gt Project submeny för att skapa ett nytt projekt. 2. Välj Win32 för projekttyperna: och Win32 Console Application för mallarna. Sätt projekt och lösningsnamn. Justera projektplatsen om det behövs och klicka på OK. 3. Klicka på Nästa för Win32 Application Wizard Overview-sidan. Vi tar bort alla onödiga projektobjekt. 4. På programsidan väljer du Tomt projekt för alternativen Extra. Lämna andra som givna och klicka på Slutför. 5. Nästa måste vi lägga till en ny källfil. Klicka på Projektmeny gt Lägg till ny undermeny eller välj projektmappen i Solution Explorer gt Välj Lägg till meny gt Välj Ny undermeny. 6. Välj C File (.cpp) för mallarna. Ange källfilnamnet och klicka på Lägg till. Även om tillägget är. cpp, kommer Visual C IDE att känna igen att källkoden som används är C baserad på alternativet Kompilera som C-kod (TC) som kommer att ställas in på projektegenskapssidan senare. 7. Lägg nu till källkoden enligt nedan. Ett urval av välj () returvärde int recvTimeOutTCP (SOCKET uttag, lång sekund, lång usec)
No comments:
Post a Comment