my_lab6

advertisement
ФЕДЕРАЛЬНОЕ АГЕНСТВО ПО ОБРАЗОВАНИЮ РФ
ГОСУДАРСТВЕННОЕ ОБРАЗОВАТЕЛЬНОЕ УЧРЕЖДЕНИЕ ВЫСШЕГО
ПРОФЕССИАНАЛЬНОГО ОБРАЗОВАНИЯ
МОСКОВСКИЙ ГОСУДАРСТВЕННЫЙ ИНСТИТУТ РАДИОТЕХНИКИ,
ЭЛЕКТРОНИКИ И АВТОМАТИКИ
(ТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ)
Факультет Кибернетики
Кафедра Интеллектуальных
технологий и систем
Лабораторная работа №6
Дисциплина: Сетевые технологии
Тема: «Параллельный сервер ТСР»
Студент: Ижбулатов Р.М.
Группа ИИ-1-03
Руководитель: Торхова Н.А.
Москва 2007.
Задание
1. Разработать параллельный эхо – сервер
Его функции:
- после установки соединения с каждым клиентом, порождая новый процесс thread в
котором происходит взаимодействие с этими клиентами;
- createthread под Windows;
- fork под Unix;
- сервер получает данные от клиента и отсылает их в неизмененном виде клиенту.
2. Реализовать текстовый клиент
Его функции:
- клиент считывает строку текста из стандартного потока ввода и отсылает ее серверу;
- клиент считывает отраженную строку из сети и выводит ее в стандартный поток
вывода.
3. С помощью реализованного эхо сервера и клиента, исследовать:
- что происходит с клиентом, если процесс сервера завешен до завершения клиента;
- что происходит с сервером, если процесс клиента завершен некорректно до
завершения сервера.
1. Echo-сервер
#if defined(WIN32)
#include <WinSock2.h>
#pragma comment(lib,"ws2_32.lib")
#endif
#include <stdio.h>
#if defined(WIN32)
DWORD WINAPI ThreadProc(LPVOID lpParameter);
#endif
int main(int argc, char **argv)
{
if (argc < 3)
{
printf("echo server v0.1\nusage: echo_server.exe <bindaddress> <bindport>\n");
return 0;
}
#if defined(WIN32)
WSADATA wsaData;
WORD wVersionRequested = MAKEWORD( 2, 2 );
int err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 )
{
printf("can't find usable wsock32.dll\n");
return 1;
}
if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2 )
{
printf("wsock32.dll of wrong version\n");
WSACleanup();
return 2;
}
#endif
SOCKET listener = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if (listener == 0)
{
printf("failed to create socket\n");
return 3;
}
sockaddr_in listener_addr;
listener_addr.sin_family = AF_INET;
listener_addr.sin_addr.S_un.S_addr = inet_addr(argv[1]);
listener_addr.sin_port = htons(atoi(argv[2]));
int ret = bind(listener,(const sockaddr*)&listener_addr,sizeof(listener_addr));
if (ret != 0)
{
printf("failed to bind socket\n");
return 4;
}
ret = listen(listener,SOMAXCONN);
if (ret != 0)
{
printf("failed to put socket into listening state\n");
return 5;
}
while (1)
{
sockaddr_in client_addr;
int sizeofclient_addr = sizeof(client_addr);
SOCKET *client_sock = (SOCKET *)malloc(sizeof(SOCKET));
*client_sock = accept(listener,(sockaddr*)&client_addr,&sizeofclient_addr);
if (*client_sock != INVALID_SOCKET)
{
#if defined(WIN32)
CreateThread(NULL,0,ThreadProc,(LPVOID)client_sock,0,NULL);
#endif
}
else
{
printf("failed to accept the connection\n");
}
}
return 0;
}
#if defined(WIN32)
DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
SOCKET *s = (SOCKET*)lpParameter;
char buf[1024];
memset(buf,0,1024);
int rlen,slen;
printf("client thread (socket %d) is ready\n",*s);
while (1)
{
rlen = recv(*s,buf,1024,0);
printf("%10d %10d> %s\n",rlen,*s,buf);
if (rlen == 0)
{
printf("socket %d closed the connection\n",*s);
closesocket(*s);
break;
}
else if (rlen == SOCKET_ERROR)
{
printf("recv socket error at socket %d\n",*s);
closesocket(*s);
break;
}
slen = send(*s,buf,rlen,0);
printf("%10d %10d< %s\n",rlen,*s,buf);
if (rlen == SOCKET_ERROR)
{
printf("send socket error at socket %d\n",*s);
closesocket(*s);
break;
}
memset(buf,0,rlen);
}
return 0;
}
#endif
2. Echo-клент
#if defined(WIN32)
#include <WinSock2.h>
#pragma comment(lib,"ws2_32.lib")
#endif
#include <stdio.h>
int main(int argc, char **argv)
{
if (argc < 3)
{
printf("echo client v0.1\nusage: echo_client.exe <servaddress> <servport>\n");
return 0;
}
#if defined(WIN32)
WSADATA wsaData;
WORD wVersionRequested = MAKEWORD( 2, 2 );
int err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 )
{
printf("can't find usable wsock32.dll\n");
return 1;
}
if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2 )
{
printf("wsock32.dll of wrong version\n");
WSACleanup();
return 2;
}
#endif
SOCKET client = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if (client == 0)
{
printf("failed to create socket\n");
return 3;
}
sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_addr.S_un.S_addr = inet_addr(argv[1]);
server_addr.sin_port = htons(atoi(argv[2]));
int ret = connect(client,(const sockaddr*)&server_addr,sizeof(server_addr));
if (ret != 0)
{
printf("failed to connect to %s:%s\n",argv[1],argv[2]);
return 5;
}
char buf[1024];
int slen,rlen;
while (1)
{
scanf("%s",buf);
int blen = strlen(buf);
if (strcmp(buf,"QUIT") == 0)
{
printf("QUIT input from user, closing socket...\n");
closesocket(client);
break;
}
slen = send(client,buf,blen,0);
printf("%10d< %s\n",slen,buf);
if (slen == SOCKET_ERROR)
{
printf("server socket error\n");
break;
}
rlen = recv(client,buf,1024,0);
printf("%10d>%s\n",rlen,buf);
if (rlen == 0)
{
printf("server closed the connection\n");
break;
}
else if (rlen == SOCKET_ERROR)
{
printf("server socket error\n");
break;
}
}
closesocket(client);
return 0;
}
3. Исследование работы сервера и клиента
На рисунке показан вывод сервера в результате следующей цепочки событий:
 Сервер слушает.
 Клиент 1 соединяется. Сервер принимает соединение, создаёт тред.
 Сервер продолжает слушать.
 Клиент 2 соединяется. Сервер принимает соединение, создаёт тред.
 Сервер продолжает слушать.
 Клиент 1 посылает данные. Сервер отсылает их обратно клиенту.
 Клиент 2 посылает данные. Сервер отсылает их обратно клиенту.
 Клиент 1 умирает.
 Сервер получает данные. Сервер отсылает данные обратно клиенту.
Сервер получает ошибку сокета. Сервер закрывает сокет и тред.
 Клиент 2 закрывает сокет. Сервер закрывает сокет и тред.
Для аномалии (сервер получает строку «OWRLD.» ещё один раз, после того,
как Клиент 2 умер) внятного объяснения найдено не было.
На рисунке показан вывод клиента в результате следующей цепочки событий:
Сервер слушает.
Клиент соединяется. Сервер принимает соединение, создаёт тред.
Клиент посылает данные. Сервер отсылает их обратно клиенту.
Сервер умирает.
Клиент посылает данные. Сокет клиента сообщает об ошибке.
Клиент закрывает сокет и закрывается.
Download