СПО в российских школах

Команда ALT Linux рассказывает о внедрении свободного программного обеспечения в школах России
Март 18, 2011

BASIC-256. Глава 20

Методические материалы
Автор: Владимир Черный

Этой главой мы завершаем публикацию перевода книги Джеймса Рено. Далее в книге только технические приложения. Всю эту информацию можно взять из справочника внутри самой программы или из сети. Эту главу перевел Владимир Черный.
Оглавление:

Где взять BASIC-256

Глава 20. Сетевые соединения

В этой главе мы обсудим как использовать сетевые возможности BASIC-256. Сетевые функции в BASIC-256 реализованы как простое соединение через сокет с использованием TCP протокола (Transmission Control Protocol — протокол управления передачей). Здесь вы не найдете полного введения в программирование для TCP/IP сокетов.

Соединение с сокетом

Сетевые сокеты создают соединение между двумя компьютерами или программами. Пакеты с информацией могут быть отправлены или получены в двух направлениях через такое соединение.


Рисунок 35 Взаимодействие между сокетами.

Когда вы звоните по телефону, то вы (как клиент) должны знать номер телефона абонента, кому вы звоните (он — сервер). Мы называем такие номера — IP-адрес. BASIC-256 использует IP-адреса версии 4, которые обычно записывают четырьмя десятичными числами, разделенными точкой (A.B.C.D, где A,B,C и D в диапазоне от 0 до 255).

Дополнительно к IP-адресу сервера, клиент и сервер должны общаться через определенный порт. Можно представлять порт, как дополнительный номер к многоканальному телефонному номеру. Если вам (как клиенту) нужен определенный человек в большой компании (имеющей один общий входящий номер), то вам необходимо набрать дополнительно внутренний номер (порт) в ответ на сообщение (телефонного сервера) о соединении с общим номером компании (IP-адресом).

Номера портов могут быть любыми в диапазоне от 0 до 65535, но обычно порты в диапазоне от 0 до 1023 заняты различными системными службами (приложениями), поэтому такие порты не следует использовать.

Пример простого сервера и клиента.

1 # simple_server.kbs пример сервера
2 print "Прием запросов по порту 9999 на IP:" + netaddress()
3 NetListen 9999
4 NetWrite "Тестовое сообщение простого сервера."
5 NetClose

Программа 106 Простой сервер

1 # simple _client.kbs пример клиента
2 input "Введите IP-адрес сервера: ", addr$
3 if addr$ = "" then addr$ = "127.0.0.1"
4 #
5 NetConnect addr$, 9999
6 print NetRead
7 NetClose

Программа 107 Простой клиент.

Прием запросов по порту 9999 на IP:10.1.2.103

Пример вывода программы 106 Простой сервер

Введите IP-адрес сервера:
Тестовое сообщение простого сервера.

Пример вывода программы 107 Простой клиент

netaddress
netaddress()

Эта функция возвращает числовой Ipv4 адрес сетевого компьютера

netlisten номер_порта
netlisten (номер_порта)
netlisten номер_сокета, номер_порта
netlisten (номер_сокета, номер_порта)

Открывает сетевое соединение (со стороны сервера) на указанном порту и ожидает соединений от других программ. Если номер_сокета не указан, используется нулевой (0) номер.

netclose
netclose()
netclose номер_сокета
netclose (номер_сокета)

Завершает указанное сетевое соединение (сокет). Если номер_сокета не указан, сокет с номером ноль (0) будет закрыт.

netwrite строка
netwrite (строка)
netwrite номер_сокета, строка
netwrite (номер_сокета, строка)

Посылает текстовое сообщение в указанное сетевое соединение. Если номер_сокета не указан, используется нулевой (0) номер.

netconnect имя_сервера, номер_порта
netconnect (имя_сервера, номер_порта)
netconnect номер_сокета, имя_сервера, номер_порта
netconnect (номер_сокета, имя_сервера, номер_порта)

Открывает соединение с сервером со стороны клиента по указанному порту. В параметре имя_сервера указывается IP адрес или сетевое имя сервера. Если номер_сокета не указан, используется нулевой (0) номер.

netread
netread()
netread (номер_сокета)

Читает данные из указанного сетевого соединения и возвращает в виде текстовой строки. Эта функция является блокирующей — она ждет, пока данные не будут получены. Если номер_сокета не указан, используется нулевой (0) номер.

Сетевой чат

Следующий пример использует еще одну сетевую функцию (netdata). Использование этой новой функции позволит нашему сетевому клиенту обрабатывать такие события, как нажатия клавиш и чтение сетевых данных только тогда, когда они действительно есть.

Программа сетевого чата (программа 108) комбинирует в себе и свойства сервера и свойства клиента. Если при запуске программы она не сможет соединиться с сервером, это событие будет перехвачено и, программа сама станет сервером. Это один из многих способов дать возможность одной программе выполнять как клиентскую, так и серверную роли.

 1 # chat.kbs чат
 2 # использует порт 9999 когда работает сервером
 3
 4 input "Адрес сервера чата (ввод для локальной машины)?", addr$
 5 if addr$ = "" then addr$ = "127.0.0.1"
 6 #
 7 # Пробуем соединиться с сервером, если неудачно - становимся сервером сами
 8 OnError startserver
 9 NetConnect addr$, 9999
10 OffError
11 print "Соединение с сервером установлено"
12
13 chatloop:
14 while true
15     # получаем код нажатой клавиши и отсылаем его
16     k = key
17     if k <> 0 then
18         gosub show
19         netwrite string(k)
20     end if
21     # получаем данные из сети и показываем их
22     if NetData() then
23         k = int(NetRead())
24         gosub show
25     end if
26     pause .01
27 end while
28 end
29
30 show:
31 if k=16777220 then
32     print
33 else
34     print chr(k);
35 end if
36 return
37
38 startserver:
39 OffError
40 print "Сервер запущен, ждем чат-клиента"
41 NetListen 9999
42 print "Клиент установил соединение"
43 goto chatloop
44 return

Программа 108 Сетевой чат

Запустите две копии BASIC-256 с программой 108 Сетевой чат. На первой запущенной копии заработает сервер, а на второй клиент. На клиенте напишите «Привет сервер!», а на сервере напишите в ответ «Привет клиент!». Вывод программы для сервера и для клиента приведены ниже.


Адрес сервера чата (ввод для локальной машины)?
Сервер запущен, ждем чат-клиента
Клиент установил соединение
ПРИВЕТ СЕРВЕР !
ПРИВЕТ КЛИЕНТ !

Пример вывода программы 108.1 Сетевой чат со стороны сервера

Адрес сервера чата (ввод для локальной машины)?
Соединение с сервером установлено
ПРИВЕТ СЕРВЕР !
ПРИВЕТ КЛИЕНТ !

Пример вывода программы 108.2 Сетевой чат со стороны клиента.

netdata
netdata()

Возвращает истину (true), если есть сетевые данные ожидающие чтения. Это позволяет программе продолжать работать без ожидания прибытия сетевого пакета.

Большая программа этой главы создает сетевую аркадную игру в танки для двух игроков.

У каждого из игроков на экране имеется белый танк (свой) и черный танк (чужой). Используя стрелки можно управлять движением танка. Стреляем пробелом.


 1 # battle.kbs танковое сражение
 2 # используем порт 9998 когда сервер
 3
 4 kspace = 32
 5 kleft = 16777234
 6 kright = 16777236
 7 kup = 16777235
 8 kdown = 16777237
 9 dr = pi / 16 # смена направление
10 dxy = 2.5 # скорость передвижения
11 scale = 20 # размер танка
12 shotscale = 4 # размер снаряда
13 shotdxy = 5 # скорость снаряда
14 port = 9998 # номер порта для связи с сервером
15
16 dim tank(30)
17 tank = {-1,-.66, -.66,-.66, -.66,-.33, -.33, -.33, 0,-1, .33,-.33, .66,-.33, .66,-.66, 1,-.66, 1,1, .66,1, .66,.66, -.66,.66, -.66,1, -1,1}
18 dim shot(14)
19 shot = {0,-1, .5,-.5, .25,0, .5,.75, -.25,.75, -.25,0, -.5,-.5}
20
21 print "Танковое сражение - вы на белом танке."
22 print "Ваша задача поразить выстрелом черный"
23 print "танк. Используйте стрелки для перемещения"
24 print "и пробел для стрельбы."
25 print
26 input "Адрес сервера (ввод для локальной машины)?", addr$
27 if addr$ = "" then addr$ = "127.0.0.1"
28
29 # Пробуем соединиться с сервером, если неудачно - становимся сервером сами
30 OnError startserver
31 NetConnect addr$, port
32 OffError
33 print "Соединение с сервером установлено"
34
35 playgame:
36
37 myx = 100
38 myy = 100
39 myr = 0
40 # Позиция снаряда (для себя): направление и оставшееся расстояние
41 # (снарядов нет, если mypl=0)
42 mypx = 0
43 mypy = 0
44 mypr = 0
45 mypl = 0
46 yourx = 200
47 youry = 200
48 yourr = pi
49 # Позиция снаряда (для противника): направление и оставшееся расстояние
50 # (снарядов нет, если yourpl=0)
51 yourpx = 0
52 yourpy = 0
53 yourpr = 0
54 yourpl = 0
55 gosub writeposition
56
57 fastgraphics
58 while true
59     # Получаем значение нажатой клавиши и перемещаем танк на экране
60     k = key
61     if k <> 0 then
62         if k = kup then
63             myx = myx + sin(myr) * dxy
64             myy = myy - cos(myr) * dxy
65         end if
66         if k = kdown then
67             myx = myx - sin(myr) * dxy
68             myy = myy + cos(myr) * dxy
69         end if
70         if k = kspace then
71             mypr = myr
72             mypx = myx + sin(mypr) * scale
73             mypy = myy - cos(mypr) * scale
74             mypl = 100
75         end if
76         if myx < scale then myx = graphwidth - scale
77         if myx > graphwidth-scale then myx = scale
78         if myy < scale then myy = graphheight - scale
79         if myy > graphheight-scale then myy = scale
80         if k = kleft then myr = myr - dr
81         if k = kright then myr = myr + dr
82         gosub writeposition
83     end if
84     # перемещаем свой снаряд (если есть снаряды)
85     if mypl > 0 then
86         mypx = mypx + sin(mypr) * shotdxy
87         mypy = mypy - cos(mypr) * shotdxy
88         if mypx < shotscale then mypx = graphwidth - shotscale
89         if mypx > graphwidth-shotscale then mypx = shotscale
90         if mypy < shotscale then mypy = graphheight - shotscale
91         if mypy > graphheight-shotscale then mypy = shotscale
92         if (mypx-yourx)^2 + (mypy-youry)^2 < scale^2 then
93             NetWrite "!"
94             print "Противник убит, Игра закончена."
95             end
96         end if
97         mypl = mypl - 1
98         gosub writeposition
99     end if
100     # Получаем из сети позицию
101     gosub getposition
102     #
103     gosub draw
104     #
105     pause .1
106 end while
107
108 writeposition: ###
109 # 10 символов для x, 10 символов для y, 10 символов для r (поворот)
110 position$ = left(myx + " ",10)+left(myy + " ",10)+left(myr + " ",10)+left(mypx + " ",10)+left(mypy + " ",10)+left(mypr + " ",10)+left(mypl + " ",10)
111 NetWrite position$
112 return
113
114 getposition: ###
115 # Получаем из сети позицию и устанавливаем переменные для противника
116 while NetData()
117     position$ = NetRead()
118     if position$ = "!" then
119         print "Вы убиты. Игра окончена."
120         end
121     end if
122     yourx = 300 - float(mid(position$,1,10))
123     youry = 300 - float(mid(position$,11,10))
124     yourr = pi + float(mid(position$,21,10))
125     yourpx = 300 - float(mid(position$,31,10))
126     yourpy = 300 - float(mid(position$,41,10))
127     yourpr = pi + float(mid(position$,51,10))
128     yourpl = pi + float(mid(position$,61,10))
129 end while
130 return
131
132 draw: ###
133 clg
134 color green
135 rect 0,0,graphwidth,graphheight
136 color white
137 stamp myx, myy, scale, myr, tank
138 if mypl > 0 then
139     stamp mypx, mypy, shotscale, mypr, shot
140 end if
141 color black
142 stamp yourx, youry, scale, yourr, tank
143 if yourpl > 0 then
144     color red
145     stamp yourpx, yourpy, shotscale, yourpr, shot
146 end if
147 refresh
148 return
149
150 startserver:
151 OffError
152 print "Сервер запущен, ожидаем присоединения клиента"
153 NetListen port
154 print "Клиент соединился с сервером"
155 goto playgame
156 return

Программа 109 Танковое сражение по сети1


Пример графического экрана программы 109 Танковое сражение по сети.

———————————————-
1Программа нуждается в доработке: а) Выстрел в сторону может попасть в противника, т. к. поле рассматривается как сферическое, при этом снаряд может пройти и через ваш танк, не причинив ему вреда, что довольно странно б) Если первый выстрел еще не долетел, а вы выстрелили вновь — первый выстрел пропадет (прим. редактора).

============================

Где скачать BASIC-256:

Для дистрибутивов ALT Linux

Windows версия
http://basic256.org (http://www.sourceforge.net/projects/kidbasic)

Как установить BASIC-256 в Linux

Для Альт Линукс: настроить репозиторий и обновить/установить пакет через synaptic или apt
Для rpm-based дистрибутивов: rpm -Uvh <имя_пакета>.rpm

Комментарии (6) к “BASIC-256. Глава 20”

  1. Компилятор Gambas IDE, входящий в состав AltLinux Юниор (gnome), ориентирован на синтаксис Basic256?
    Практически VBasic :)

  2. В Юниоре и сам Basic256 имеется.

  3. oleg говорит:
    Март 23, 2011, 5:52 пп

    Есть-есть..
    Просто заглянул в Gambas -> набросал графическое приложение на Basic -> скомпилировал -> запустил = работает :)
    В gambas удивила библиотека форм по задачам, от переключателей, прогресса до БД и web. В path добавил каталог и запускай свои программки по alt-f2, или с рабочего стола (по файл-ссылке).
    Вот только как быть с открытостью? Код двоичный.

  4. Gambas и создавался как свободная альтернатива VBasic. Жаль только, что он не кроссплатформенный…

  5. oleg говорит:
    Март 31, 2011, 6:55 пп

    Сегодня первую задачку доделал в Gambas :)
    Описание закончу — опубликуем..
    Первое впечатление:
    1. по работе с директориями и файлами с VB есть различия.
    2. математ. функции, работа со строками — идентична.
    3. Среда значительно проще Lazarus, т.е. с первого занятия (после получения навыков алгоритмики, конечно) можно садить учеников и конструировать.
    4. Поддержка БД
    5. В рунете пока мало информационных ресурсов по Gambas
    6. При сборки rpm-пакетов представлены только ОС Fedora, Mandriva и Suse

  6. oleg говорит:
    Март 31, 2011, 7:08 пп

    Для нас уже кросплатформенность состоит в выборе между AltLinux, Ubuntu, Suse.. :)
    Думаю, что если вести занятия по программированию в старших классах, или кружках, первых курсах вуза, то ученики справятся в установке Линукс в качестве второй ОС, как минимум.
    p.s. а Gambas интересен, руки чешутся :)

Оставьте комментарий