Сделать стартовой  Добавить в избранное  Форум   Реклама   Написать нам   DLE хостинг крупных порталов 

RSS   English   Russian   

:: Главное Меню
· > Главная
· > Инт. Новости
· > События за 24 часа
· > Программы
· > Мобильный раздел
· > Видео фильмы
· > Скачать фильмы
· > Интернет книги
· > Безопасность
· > Игры
· > Музыка альбомы
· > Вебмастер
· > Рабочий стол
· > Электронные платежи
· > ОС Linux
· > Краткие номера ICQ
· > Развлечения
· > Полезная информация
· > Юмор
· > Своими руками
· > Технологии HI-TECH

:: Поиск
  
Расширенный поиск...

Скачать фильмы за 20 мин.





Скачать фильмы Фильмы онлайн Скачать кино Скачать новые фильмы Скачать фильмы Кино скачать DVD скачать фильмы Фильмы 2008 онлайн кино Кинопоиск скачать
Особо опасен Бэтмен 3 Хэнкок DVDRip Железный человек На краю Света Удачи Чак Скачать новые фильмы, сериалы, мультфильмы бесплатно Наше кино Боевики 2008


Начни день с нами занеси наш сайт в закладки -)
 :: Связь с SMSC.
 
Итак, мы выделили следующие задачи:

Установка соединения по TCP/IP с сервис-центром.

Формирование пакетов в формате выбранного нами протокола.

«Разбор» (parse) пакетов в формате выбранного протокола.
В данной статье мы сосредоточимся на первой задаче. Вообще-то, мы не собирались здесь вдаваться в детали программирования сокетов (sockets), полагая, что читатели знакомы с данным вопросом. Однако думается, что несколько слов сказать все же стоит. Тем не менее мы настоятельно (а как же :) советуем тем, кто не знаком с данным вопросом, изучить его подробнее применительно к той ОС под которой придется программировать.

(для UNIX см. например http://world.std.com/~jimf/papers/sockets/sockets.html)
мы же приведем простую реализацию, которая нам понадобится в дальнейшем. Те же, кто уже сталкивался с программированием сокетов могут запросто пропустить данную статью, обратившись, может быть, к нескольким последним абзацам.

2.2 Общие принципы. Связь по TCP/IP устанавливается по принципу "точка-точка"; инициирующая сторона называется клиентом, принимающая -- сервером. Сервер постоянно находится в ожидании входящих соединений (как говорят, "слушает" -- listening), клиент же посылает запрос на установление связи, используя IP-номер (IP-адрес) сервера и номер порта. IP-адрес это тридцатидвухразрядное число, представляемое обычно в т. н. dotted нотации:

XXX.XXX.XXX.XXX
(байты разделены точками, кажда из групп XXX может принимать значения от 0 до 255). Номер же прота можно рассматривать как указание на конкретный сервис данного узла. Таким образом, для установки соединения клиенту необходимо знать пару чисел IP-адрес:порт (например 192.18.97.241:80 дает нам www-сервер компании Sun Microsystems :). Мы не станем здесь останавливаться на службе доменных имен (предыдущий пример можно записать проще:
http://www.sun.com:80), URL и прочем, полагая, что читателю это знакомо. Заметим только, что существуют стандартные соглашения на присваивание номеров портов сервисам (в предыдущем примере использован порт 80 -- http; можно упомянуть порт 21 -- ftp, 23 -- telnet и 25 -- smpt), посему
для "нестандартных" сервисов рекомендуется брать "большие" номера (мы предпочитаем номера начиная с 8100). Кстати, из вышесказанного видно, что работа с сокетами на клиентской и серверной сторонах различна. Мы начнем (сюрприз!) с серверной части.


2.2 Сервер. Простейшая реализация TCP/IP сервера может быть представлена следующим кодом (socktest.c):


--------------------------------------------------------------------------------

#ifdef _WIN32 #include #else #include #include #include #include #include #include typedef struct sockaddr SOCKADDR; typedef struct sockaddr_in SOCKADDR_IN; #define SOCKET_ERROR -1 #define INVALID_SOCKET -1 #define closesocket(s) close(s) #endif /* _WIN32 */


#include


int main(int argc, char** argv)
{ SOCKADDR_IN sockaddr;
SOCKADDR_IN descr;
int addr_len = sizeof(SOCKADDR_IN);


#ifdef _WIN32
SOCKET sock;
SOCKET newsock;
WSADATA WSAData;

/* Startup socket library */
if (WSAStartup(MAKEWORD(1,1), &WSAData) != 0)
perror("Can't initialize socket library"); #else
int sock;
int newsock;
#endif /* _WIN32 */
/* create socket */
sock = socket(PF_INET, SOCK_STREAM, 0);
if (sock == INVALID_SOCKET) { perror("Can't open socket");
return 1;
}
/* filling up sockaddr structure */
sockaddr.sin_family = AF_INET;
sockaddr.sin_addr.s_addr = INADDR_ANY;
sockaddr.sin_port = htons(8100);
/* bind socket */
if (bind(sock, (const SOCKADDR *)&sockaddr, sizeof(SOCKADDR_IN))) {
perror("Can't bind socket");
closesocket(sock);
return 1;
}


/* start listening */
if (listen(sock, 1) == SOCKET_ERROR) {
perror("Can't start listening");
closesocket(sock);
return 1;
}
else {
/* accept connection (note that accept() is
the blocking call) */
newsock = accept(sock, (SOCKADDR *)
&descr, &addr_len);

if (newsock != INVALID_SOCKET) {
printf("Connection is accepted. Peer: %
s ", inet_ntoa(descr.sin_addr));
if (send(newsock, "Hello from server",
strlen("Hello from server"), 0) ==
SOCKET_ERROR)
perror("Send operation failed");
}
else
perror("Can't accept connection");
closesocket(sock);
closesocket(newsock);
}


return 0;
}


--------------------------------------------------------------------------------


Мы постарались сделать код переносимым (по крайней мере между Windows и Linux. Для того, чтобы собрать данный пример под Windows мы должны указать компоновщику на библиотеку wsock32.lib). Как видно из предыдущего примера, "открытие порта на прослушку" -- операция достаточно простая: необходимо создать сокет (socket(2)), заполнить и связать с сокетом структуру sockaddr_in (bind(2)), после чего вызвать listen(2). В данном примере сервер начинает "слушать" по порту 8100. По приходу запроса отрабатывает функция accept(2), которая создает новый сокет, оставляя "старый" готовым к приему нового соединения. Новый сокет готов к приему-передаче данных, мы посылаем приветствие и закрываем оба сокета (тонко, правда? ;).

Обратим внимание на то, что accept является блокирующим вызовом, т. е. поток исполнения не проходит ниже этой строчки, пока не принято входящее соединение, и наша программа не может в это время делать ничего, кроме как "болтаться в accept'е". Кроме того, данный пример написан так, что принимает только одно соединение. Мы могли бы не закрывать первый сокет, а снова вызвать с ним accept для приема второго соединения, однако проблема блокировки вызовом accept все равно не была бы решена (несколько забегая вперед, заметим, что и функция приема данных из сокета recv(2) также является блокирующей). Часто данную проблему снимают организуя многопоточное (multithreaded) приложение, в котором каждое соединение обрабатывается в собственном потоке или, под UNIX, используют вызов разделения процесса fork(2) (кстати, ежели кто не понял, зачем двойки в скобках, -- это означает вторую секцию руководства). Добиться переносимости такого кода -- задача совсем нетривиальная, мы же пока не хотим привязываться к платформе, насколько это возможно, и потому воспользуемся вызовом select(2), который присутствует и в UNIX и в Windows. Функция select ожидает изменения статуса набора дескрипторов (в Windows поддерживаются только сокеты, а в UNIX -- файловые дескрипторы, коими сокеты и являются). Кроме того, нам потребуется перевести наши сокеты в неблокирующее состояние (non-blocking mode).


Все вышесказанное отражено в следующем примере, состоящем из трех файлов (по прежнему, в Windows следует подключать библиотеку wsock32.lib):


smsce.h
--------------------------------------------------------------------------------
#ifndef _SMSCE_H_

#ifdef _WIN32

#include
#define socklen_t int
#else
#include "unisock.h"
#include
#include
#endif

#define _SMSCE_H_
#endif /* _SMSCE_H_ */
--------------------------------------------------------------------------------
smsce.cpp
--------------------------------------------------------------------------------
#include
#include
#include
#include "smsce.h"
#define SERVER_PORT 8200
#define RECVBUFSIZ 4096
using namespace std;
bool process_data(SOCKET sock)
{
static char buf[RECVBUFSIZ];
int received;
if ((received = recv(sock, buf, RECVBUFSIZ,
0)) != SOCKET_ERROR) {
buf[received] = '';
cout << (char *)buf << flush;
return true;
}

return false;
}
static void shutdown_socket(SOCKET *s)
{
if (*s != INVALID_SOCKET) {
shutdown (*s, SD_BOTH);
closesocket(*s);
*s = INVALID_SOCKET;
}
}
int main(int argc, char **argv)
{
#ifdef _WIN32
WSADATA WSAData;

/* Startup socket library */
if (WSAStartup(MAKEWORD(1,1), &WSAData) != 0)

perror("Can't initialize socket library");#endif

// list for server clients
typedef list CL;
CL clients;
CL::iterator ii;
struct timeval tv;
fd_set readfds;
fd_set exfds;
SOCKET ssocket;
SOCKET accepted;
SOCKET maxfd;
bool true_value = true;
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(SERVER_PORT);
addr.sin_addr.s_addr = htonl(INADDR_ANY);

// Creating the socket and setting it's optioins
ssocket = socket(PF_INET, SOCK_STREAM,

IPPROTO_TCP);
if (ssocket == INVALID_SOCKET) {
perror("Can't create socket");
return 1;
}
setsockopt(ssocket, SOL_SOCKET, SO_REUSEADDR, (char *) &true_value, sizeof (true_value));
#ifdef _WIN32
ioctlsocket(ssocket, FIONBIO, (unsigned long *)&true_value); // Set to non-block mode #else
fcntl(ssocket, F_SETFL, O_NONBLOCK); // Set to non-block mode
#endif // _WIN32
// Binding
if (bind(ssocket, (struct sockaddr *) &addr, sizeof (addr)) == SOCKET_ERROR) { perror("Can't start listening"); return 1;
}
// sockaddr for client socket
struct sockaddr_in ca;
int cal = sizeof(ca);
// Start listening
if (listen (ssocket, SOMAXCONN) ==
SOCKET_ERROR) { perror("Can't start listening"); return 1;
}
while (true) {
// Trying to accept connection (non-blocking mode)
// Please note that if no incoming connection presents at non-blocking
// socket accept returns with some error like EAGAIN or EWOULDBLOCK
if ((accepted = accept(ssocket, (struct sockaddr *) &ca, (socklen_t *)&cal)) != SOCKET_ERROR)
clients.push_back(accepted);

// Preparing descriptor sets
FD_ZERO(&readfds);
FD_ZERO(&exfds);
FD_SET(ssocket, &exfds);
tv.tv_sec = 1;
tv.tv_usec = 0;
maxfd = ssocket;
for (ii = clients.begin(); ii != clients.end();
++ii) {
FD_SET((SOCKET )*ii, &readfds);
FD_SET((SOCKET )*ii, &exfds);
maxfd = max(maxfd, (SOCKET )*ii);
}


// select failing breaks the work
if (select(maxfd + 1, &readfds, NULL,
&exfds, &tv) == -1) break;

// On exception in server socket also breaks immediately
if(FD_ISSET(ssocket, &exfds)) break;
// Test events on client sockets
for (ii = clients.begin(); ii != clients.end(); ++ii) {
if (FD_ISSET(*ii, &exfds)) {
if (*ii != INVALID_SOCKET)
shutdown_socket(&(*ii));
if ((ii = clients.erase(ii)) == clients.end()) break;
}
if (FD_ISSET(*ii, &readfds) && !
process_data(*ii)) { if (*ii != INVALID_SOCKET)
shutdown_socket(&(*ii));
if ((ii = clients.erase(ii)) == clients.end()) break;
}
// Send data
if (*ii != INVALID_SOCKET)
if (send(*ii, "Connection is established ",
strlen("Connection is established "), 0)
== SOCKET_ERROR) if ((ii = clients.erase(ii)) == clients.end()) break;
}
}
for (ii = clients.begin(); ii != clients.end(); ++ii)
if (*ii != INVALID_SOCKET)
shutdown_socket(&(*ii));
shutdown_socket(&ssocket);
return 0;
}

--------------------------------------------------------------------------------
unisock.h
--------------------------------------------------------------------------------
#ifndef _UNISOCK_H_
#ifndef _WIN32
#include
#include
#include
#include
#include
#include
typedef int SOCKET;
typedef struct sockaddr SOCKADDR;
typedef struct sockaddr_in SOCKADDR_IN;
#define SOCKET_ERROR -1
#define INVALID_SOCKET -1

#define SD_RECEIVE 0x0
#define SD_SEND 0x1
#define SD_BOTH 0x2

#define closesocket(s) close(s)

#endif /* _WIN32 */


#define _UNISOCK_H_
#endif /* _UNISOCK_H_ */


--------------------------------------------------------------------------------
В этом примере мы получили возможность обрабатывать несколько входящих соединений (хотя, если в канале нет данных от клиента, то select ждет 1 секунду; таким образом, мы не можем отправлять данные клиентам чаще, но этого нам в дальнейшем будет достаточно) и не останавливаться на блокирующих вызовах. Интервал в 1 секунду выбран произвольно. Мы можем испытать наш сервер, набрав команду:
telnet localhost 8200 Остановить выполнение сервера можно с помощью Ctrl-C :). Разумеется, в приведенном примере еще многое можно "подрихтовать" (например, можно проверять, доступен ли сокет для записи перед вызовом send или проверять код ошибки accept), но мы объявим серверную часть готовой и перейдем, наконец, к клиенту.
2.3 Клиент. Программирование клиентских сокетов несколько проще, чем серверных. На клиенте достаточно создать сокет с помощью socket(2) и соединить с удаленной стороной с помощью connect(2). После этого сокет готов к приему и передаче данных. Просто приведем пример.

sockclient.h -------------------------------------------------------------------------------- #ifndef _SMSCE_H_ #ifdef _WIN32
#include
#define socklen_t int
#else
#include "unisock.h"
#include
#include
#define Sleep(x) usleep((unsigned long )(x * 1000))
#endif


#define _SMSCE_H_ #endif /* _SMSCE_H_ */ --------------------------------------------------------------------------------
sockclient.cpp
--------------------------------------------------------------------------------
#include
#include
#include "sockclient.h"
#define SERVER_ADDR "127.0.0.1" // localhost
#define SERVER_PORT 8200
#define RECVBUFSIZ 4096
using namespace std;

int
main(int argc, char **argv)
{
#ifdef _WIN32
WSADATA WSAData;
// Startup socket library
if (WSAStartup(MAKEWORD(1,1), &WSAData) != 0)
perror("Can't initialize socket library");
#endif
SOCKET soc;
struct sockaddr_in addr;
static char buf[RECVBUFSIZ];
int received;
addr.sin_family = AF_INET;
// Server address
addr.sin_addr.s_addr = inet_addr(SERVER_ADDR);
// Server port
addr.sin_port = htons(SERVER_PORT);


// Creating socket
if ((soc = socket(PF_INET, SOCK_STREAM,
IPPROTO_TCP)) == INVALID_SOCKET) {
perror("Can't create socket");

return 1; }
// Perform connection
if (connect(soc, (struct sockaddr *) &addr, sizeof(addr)) == SOCKET_ERROR) {
perror("Can't connect");
return 1;
}
cout << "Connection is established" << endl;
// Try to receive greeting.
// Note thar receive is the blocking call
if ((received = recv(soc, buf, RECVBUFSIZ, 0)) != SOCKET_ERROR) {
buf[received] = '';
cout << (char *)buf << flush;
}
else {
perror("Receive operation failed");
closesocket(soc);
return 1;

}
// Try to send greeting
if (send(soc, "Hello from client ",

strlen("Connection is established "), 0) ==
SOCKET_ERROR) {
perror("Hello from client ");
closesocket(soc);
return 1;
}
closesocket(soc);
return 0;
}
-------------------------------------------------------------------------------- unisock.h остался без изменений:
-------------------------------------------------------------------------------- #ifndef _UNISOCK_H_ #ifndef _WIN32
#include
#include
#include
#include
#include
#include
typedef int SOCKET;
typedef struct sockaddr SOCKADDR;

typedef struct sockaddr_in SOCKADDR_IN;
#define SOCKET_ERROR -1
#define INVALID_SOCKET -1

#define SD_RECEIVE 0x0
#define SD_SEND 0x1
#define SD_BOTH 0x2
#define closesocket(s) close(s)
#endif /* _WIN32 */

#define _UNISOCK_H_

#endif /* _UNISOCK_H_ */
--------------------------------------------------------------------------------

В этом примере мы устанавливаем соединение с нашим сервером, дожидаемся приветствия, посылаем ответное и закрываем соединение. Напомним, что recv(2) является блокирующим вызовом, что нас, вообще говоря, не устраивает. Тем не менее, мы снова можем перевести наш сокет в неблокирующее состояние и воспользоваться select. Мы так и поступим в дальнейшем, а этот пример просто показывает технику написания простейшего клиента, и мы с удовольствием обнаруживаем, что это не слишком сложно. В завершение обратим внимание на вызовы inet_addr(3) и htons(3). Первая функция дает IP-адрес по символьному его представлению, а вторая переводит short int в целое с порядком байтов, принятых в сети. Часто этот порядок совпадает с порядком байтов в машинном представлении, но может и не совпадать (имеется ввиду т. н. LSB и FSB представления). Впрочем, это уже тонкости, о которых можно почитать и в другом месте :). И наконец, можно на досуге взглянуть на функцию gethostbyname(3), которая выполняет т. н. разрешение (resolving) по имени хоста. Используя ее, мы могли бы обратиться к нашему серверу не по IP-адресу, а по его имени ("localhost").


Глава 3 Заключение. Итак, в данной статье мы выяснили, как обращаться с сокетами. Те, кто уже имел с ними дело (и набрался терпения дочитать до этого места), наверное обратили внимание на то, что мы использовали "классическую" Берклиевскую реализацию. Она хороша тем, что в большинстве случаев переносима между платформами, однако нам бы не хотелось подталкивать разработчиков к использованию именно такого подхода, тем более, что, как мы в дальнейшем увидим, для работы с SMS-протоколами это совсем необязательно, ибо они абстрагированы от деталей установки соединения. Например, те, кто программирует под Windows, могут воспользоваться функциями из семейства WSA* (если, конечно, не уснут, читая их перечень :), а программисты, привыкшие работать с MFC, возможно найдут полезным класс CSocket (правда, если Вы собираетесь использовать его в мультипоточном приложении с CWinThread, не забудьте включить заклинание:

--------------------------------------------------------------------------------
v #ifndef _AFXDLL
#define _AFX_SOCK_THREAD_STATE AFX_MODULE_THREAD_STATE #define _afxSockThreadState AfxGetModuleThreadState()
_AFX_SOCK_THREAD_STATE* pState = _afxSockThreadState;
if (pState->m_pmapSocketHandle == NULL) pState->m_pmapSocketHandle = new CMapPtrToPtr;
if (pState->m_pmapDeadSockets == NULL) pState->m_pmapDeadSockets = new CMapPtrToPtr;
if (pState->m_plistSocketNotifications == NULL)
pState->m_plistSocketNotifications = new CPtrList;



#endif
--------------------------------------------------------------------------------
в код thread'а до самой первой сокетной операции; возможно, это сэкономит Вам выходные ;). И, в конце концов, Вы можете воспользоваться компонентами (Привет, Михаил! ;), которых достаточно много и которые достаточно "бросить" на форму, особенно это касается поклонников продуктов от Borland.

Мы же на этом закончим обсуждение вопроса, еще раз напомнив о предложении внимательно его изучить, а то что-то мы увлеклись сокетами; пора переходить к содержательной части дела. В следующей статье мы попробуем построить наше первое "настоящее" SMS-приложение и добавим функциональности нашему эмулятору. Оставайтесь с нами!

Скачать этот файл по HTTP


Автор: admin - 31 мая 2003 - Комментарии (0)   







 :: Информация
  Посетители, находящиеся в группе Гости, не могут оставлять комментарии в данной новости.


Варез портал существует с 2003 - 2008 / Хостинг предоставили MacHoster.Ru

Firewall Cisco Systems, Inc


:: Вход

:: Это интересно!
Загрузка ...

:: Партнёры
· -> Gold Warez
· -> Kadet Team
· -> Interfilm.Tv
· -> Зевель.ру
· -> Timeparty
· -> Пежня.ру
· -> Soft Best.net
· -> Creep.ru
· -> Ziza.ru
· -> Goldwarez.ru
· -> Korzik.net
· -> Prikola.net
· -> LooKsZone.ru
· -> MaxDown.Ru
Реклама

Хостинг оптимизирован под DataLife движок...