 |
МОДЕРАТОР |
 |
Зарегистрирован: Пн апр 09, 2007 4:53 pm Сообщений: 11108 Благодарил (а): 4 раз. Поблагодарили: 395 раз.
|
При обмене данными по сети, необходимо понять саму суть обмена. Через сеть передается и принимается массив (поток) данных и в них должны быть специальные метки чтобы можно было этот массив разобрать на приемной стороне. Среди таких меток должны быть как минимум, команда (тип данных) и длина пакета с данными. Таким образом, при приеме массива данных из сети, будет информация, во первых о типе пакета, необходимая для его правильной обработки, а во вторых, длина пакета, необходимая чтобы точно знать каков его размер. Это можно описать примерно такой структурой. Код: 1 2 3 4
| Structure NetPacket_Header Size.u ; 2 байта. Type.u ; 2 байта. EndStructure |
Эта структура является заголовком пакета и должна быть в его начале, и за ней следуют данные. Поле Size определяет размер пакета. В данном случае, его размер не может превышать 64 КБ, но если увеличить размер поля до 4-ёх байт (тип Long), то появится возможность передавать пакеты имеющие размер до 4 ГБ. Но это нежелательно, поскольку если потеряется пакет не большого размера, то его быстрее можно будет повторно отправить. Поле Type определяет тип пакета (команду), необходимую для правильной обработки пакета на приемной стороне. Если протокол реализован поверх UDP, или другого низкоуровневого протокола, то не помешает добавить так же поле с контрольной суммой пакета, чтобы удостоверится в целостности данных. Есть еще один момент, на который необходимо обратить внимание. Пакет может быть принят не за один раз (вызов принимающей функции из сети) или наоборот, за раз может быть принято несколько пакетов, причем последний из них может быть принят не полностью. Поэтому так же необходим промежуточный буфер, в который будут записываться все данные, принимаемые из сети, а затем, по мере получения целых пакетов, уже обрабатываться. Реализация в коде (сервер и клиент) всего вышенаписанного. Для примера, реализованы две команды: Код: 1 2
| #NetPacketType_EndProg ; Завершить работу клиента. #NetPacketType_Data ; Данные. |
Прием пакетов из сети с использованием промежуточного буфера. Код: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
| Structure NetBuff_Param *Buff Len.l Pos.l EndStructure EnableExplicit Procedure NetBuff_ReallocateMemory(*Buff.NetBuff_Param, AddBytes) ; Нужно ли увеличить память под данные, принимаемые от пира? Protected Len, Pos, NewLen, *Point Protected *NewPoint, i Len = *Buff\Len Pos = *Buff\Pos *Point = *Buff\Buff If AddBytes>0 NewLen = 0 If Pos>Len Or Len-Pos < AddBytes Or *Point=0; Нужно изменить (увеличить) размер памяти. NewLen = Len+AddBytes+100 ElseIf Len-Pos > AddBytes+400 ; Памяти выдленено слишком много и надо уменьшить. NewLen = AddBytes+Pos+80 EndIf If NewLen > 0 For i=1 To 4 *NewPoint = ReAllocateMemory(*Point, NewLen) If *NewPoint *Buff\Buff = *NewPoint *Buff\Len = NewLen If *Buff\Len>NewLen *Buff\Len=NewLen EndIf Len = NewLen Break Else Delay(4) EndIf Next i EndIf EndIf ProcedureReturn Len EndProcedure Procedure NetBuff_AddMem(*Buff.NetBuff_Param, *Mem, AddBytes) ; Добавление принятых жанных от пира, в память еще необработанных сообщений. Protected NewLen NewLen=NetBuff_ReallocateMemory(*Buff, AddBytes) ; Выделение памяти If NewLen>0 And *Buff\Len >= AddBytes+*Buff\Pos ; Память выделена CopyMemory(*Mem, *Buff\Buff+*Buff\Pos, AddBytes) *Buff\Pos + AddBytes EndIf EndProcedure Procedure NetBuff_DelMem(*Buff.NetBuff_Param, DelBytes) ; Удаление принятых данных от пира, из памяти после успешной обработки сообщения. If *Buff\Buff If *Buff\Pos <= DelBytes *Buff\Pos = 0 Else If *Buff\Pos>DelBytes MoveMemory(*Buff\Buff+DelBytes, *Buff\Buff, *Buff\Pos-DelBytes) ; EndIf *Buff\Pos - DelBytes If *Buff\Pos<0 *Buff\Pos=0 EndIf EndIf EndIf EndProcedure Enumeration #NetPacketType_EndProg #NetPacketType_Data EndEnumeration Structure NetPacket_Header Size.u Type.u EndStructure Structure NetPacket_EndData Header.NetPacket_Header EndStructure Structure NetPacket_Data Header.NetPacket_Header Buff.a[0] EndStructure Procedure Net_InData(Connect, *Point, Size, *BuffInfo.NetBuff_Param) Protected InBytes, *Header.NetPacket_Header Protected Result NetBuff_AddMem(*BuffInfo, *Point, Size) Result = #False Repeat If *BuffInfo\Pos>=SizeOf(NetPacket_Header) *Header = *BuffInfo\Buff If *BuffInfo\Pos >= *Header\Size Select *Header\Type Case #NetPacketType_EndProg Protected *EndData.NetPacket_EndData = *BuffInfo\Buff Result = #True NetBuff_DelMem(*BuffInfo, *Header\Size) Case #NetPacketType_Data Protected *|/1/>Data.NetPacket_Data = *BuffInfo\Buff Debug PeekS(@*|/1/>Data\Buff[0], *|/1/>Data\Header\Size-OffsetOf(NetPacket_Data\Buff)) NetBuff_DelMem(*BuffInfo, *Header\Size) EndSelect Else Break EndIf EndIf Until *BuffInfo\Pos < SizeOf(NetPacket_Header) ProcedureReturn Result EndProcedure InitNetwork() Define Connect = OpenNetworkConnection("127.0.0.1", 2222, #PB_Network_TCP) If Connect Define *Point = AllocateMemory(65536) If *Point Define BuffInfo.NetBuff_Param\Buff = AllocateMemory(10) BuffInfo\Len=10 BuffInfo\Pos=0 If BuffInfo\Buff Repeat Define NetEvent = NetworkClientEvent(Connect) If NetEvent = #PB_NetworkEvent_Data Define InBytes = ReceiveNetworkData(Connect, *Point, 65536) If Net_InData(Connect, *Point, InBytes, @BuffInfo) Break EndIf Else Delay(10) EndIf ForEver CloseNetworkConnection(Connect) FreeMemory(BuffInfo\Buff) EndIf FreeMemory(*Point) EndIf Else Debug "Нет связи" EndIf |
Сервер для тестирования. Код: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
| Enumeration #NetPacketType_EndProg #NetPacketType_Data EndEnumeration Structure NetPacket_Header Size.u Type.u EndStructure Structure NetPacket_EndData Header.NetPacket_Header EndStructure Structure NetPacket_Data Header.NetPacket_Header Buff.a[0] EndStructure ;Header.NetPacket_Header EndData.NetPacket_EndData Procedure Send(Connect, String.s) NetPacket_Data.NetPacket_Data NetPacket_Data\Header\Size = SizeOf(NetPacket_Header)+StringByteLength(String) NetPacket_Data\Header\Type = #NetPacketType_Data SendNetworkData(Connect, @NetPacket_Data\Header, SizeOf(NetPacket_Header)) SendNetworkData(Connect, @String, StringByteLength(String)) EndProcedure If InitNetwork() = 0 MessageRequester("Error", "Can't initialize the network !", 0) End EndIf Port = 2222 *Buffer = AllocateMemory(1000) If CreateNetworkServer(0, Port) Repeat SEvent = NetworkServerEvent() If SEvent ClientID = EventClient() Select SEvent Case #PB_NetworkEvent_Connect Send(ClientID, "Первая строка") Send(ClientID, "Еще строка") Send(ClientID, "Строка № 3") Send(ClientID, "Больше нет строк") EndData\Header\Size = SizeOf(NetPacket_Header) EndData\Header\Type = #NetPacketType_EndProg SendNetworkData(ClientID, @EndData, SizeOf(NetPacket_Header)) Case #PB_NetworkEvent_Disconnect MessageRequester("PureBasic - Server", "Client "+Str(ClientID)+" has closed the connection...", 0) Quit = 1 EndSelect EndIf Until Quit = 1 MessageRequester("PureBasic - Server", "Click to quit the server.", 0) CloseNetworkServer(0) Else MessageRequester("Error", "Can't create the server (port in use ?).", 0) EndIf End |
_________________ Компьютер позволяет решать все те проблемы, которые до его изобретения не существовали. 
|
|