purebasic.info

PureBasic forum
Текущее время: Ср сен 19, 2018 2:16 pm

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 8 ] 
Автор Сообщение
 Заголовок сообщения: Прием пакетов из сети.
СообщениеДобавлено: Ср мар 27, 2013 1:12 am 
Не в сети
МОДЕРАТОР
Аватар пользователя

Зарегистрирован: Пн апр 09, 2007 4:53 pm
Сообщений: 11255
Благодарил (а): 4 раз.
Поблагодарили: 429 раз.
При обмене данными по сети, необходимо понять саму суть обмена. Через сеть передается и принимается массив (поток) данных и в них должны быть специальные метки чтобы можно было этот массив разобрать на приемной стороне. Среди таких меток должны быть как минимум, команда (тип данных) и длина пакета с данными. Таким образом, при приеме массива данных из сети, будет информация, во первых о типе пакета, необходимая для его правильной обработки, а во вторых, длина пакета, необходимая чтобы точно знать каков его размер. Это можно описать примерно такой структурой.
Код:
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  
 


_________________
Компьютер позволяет решать все те проблемы, которые до его изобретения не существовали. :) :)


Вернуться наверх
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Вс авг 18, 2013 6:47 pm 
Не в сети
профессор
Аватар пользователя

Зарегистрирован: Ср май 08, 2013 10:51 am
Сообщений: 621
Откуда: Новотроицк
Благодарил (а): 0 раз.
Поблагодарили: 1 раз.
Пункты репутации: 0
подскажите ,как работают скайпы всякие ,а лучше покажите

_________________
Порядок необходим глупцам, гений же властвует над хаосом(А.Эйнштейн ©)


Вернуться наверх
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Вс авг 18, 2013 6:52 pm 
Не в сети
МОДЕРАТОР

Зарегистрирован: Вт дек 05, 2006 8:46 am
Сообщений: 6382
Благодарил (а): 20 раз.
Поблагодарили: 198 раз.
Пункты репутации: 48
Владислав писал(а):
подскажите ,как работают скайпы всякие

А Гугл что, не пашет?
Клиент конечно можно написать, если вникнуть в протокол. Но что бы всё с нуля подобное замутить - надо денег много и специалистов. Одних серверов не напасешься.

_________________
read-only


Вернуться наверх
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Вс авг 18, 2013 6:54 pm 
Не в сети
профессор
Аватар пользователя

Зарегистрирован: Ср май 08, 2013 10:51 am
Сообщений: 621
Откуда: Новотроицк
Благодарил (а): 0 раз.
Поблагодарили: 1 раз.
Пункты репутации: 0
kvitaliy
а айпи в айпи не получится?просто в игрушках работает,мне почему-то интересно стало

_________________
Порядок необходим глупцам, гений же властвует над хаосом(А.Эйнштейн ©)


Вернуться наверх
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Вс авг 18, 2013 6:58 pm 
Не в сети
МОДЕРАТОР

Зарегистрирован: Вт дек 05, 2006 8:46 am
Сообщений: 6382
Благодарил (а): 20 раз.
Поблагодарили: 198 раз.
Пункты репутации: 48
Владислав писал(а):
в игрушках работает

В игрушках ты всегда к серверу подключаешься. Я уже тебе говорил, что можно всё, если у тебя есть выделенный сервер с белым ip

_________________
read-only


Вернуться наверх
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Вс авг 18, 2013 7:07 pm 
Не в сети
профессор
Аватар пользователя

Зарегистрирован: Ср май 08, 2013 10:51 am
Сообщений: 621
Откуда: Новотроицк
Благодарил (а): 0 раз.
Поблагодарили: 1 раз.
Пункты репутации: 0
kvitaliy
у меня есть=можно... как?

_________________
Порядок необходим глупцам, гений же властвует над хаосом(А.Эйнштейн ©)


Вернуться наверх
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Вс авг 18, 2013 7:20 pm 
Не в сети
МОДЕРАТОР

Зарегистрирован: Вт дек 05, 2006 8:46 am
Сообщений: 6382
Благодарил (а): 20 раз.
Поблагодарили: 198 раз.
Пункты репутации: 48
Владислав писал(а):
можно... как?

Изучай протокол, поднимай сервер, пиши клиенты, раздавай людям, будем говорить по твоей связи. А то скоро Скайп сдадут спецслужбам, ни какой секретности. Вся надежда на тебя.

_________________
read-only


Вернуться наверх
 Профиль  
 
 Заголовок сообщения:
СообщениеДобавлено: Вс авг 18, 2013 7:27 pm 
Не в сети
профессор
Аватар пользователя

Зарегистрирован: Ср май 08, 2013 10:51 am
Сообщений: 621
Откуда: Новотроицк
Благодарил (а): 0 раз.
Поблагодарили: 1 раз.
Пункты репутации: 0
kvitaliy
я не сказал ,что буду писать,мне просто интересно,как это делается именно на пуре

_________________
Порядок необходим глупцам, гений же властвует над хаосом(А.Эйнштейн ©)


Вернуться наверх
 Профиль  
 
Показать сообщения за:  Сортировать по:  
Начать новую тему Ответить на тему  [ Сообщений: 8 ] 

Часовой пояс: UTC + 3 часа


Кто сейчас на форуме

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 2


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  
Создано на основе phpBB® Forum Software © phpBB Group (блог о phpBB)
Сборка создана CMSart Studio
Русская поддержка phpBB