
готов лаби 4 курс 1 сим / Вычислительные системы / Lab6
.docМіністерство освіти і науки, молоді та спорту України
Кіровоградський національний технічний університет
Механіко-технологічний факультет
Кафедра: Програмного забезпечення
Дисципліна: ”Обчислювальні системи”
Лабораторна робота № 6
Тема: «Комунікаційне програмне забезпечення рівня користувача. Виклик віддаленої процедури»
Виконав: ст.гр.КІ-10-1
Перевірив: викладач
Минайленко Р.М.
Кіровоград 2013
Завдання до лабораторної роботи
Напишіть на мові С функції, які могли б використовувати як клієнтський так і серверний сурогати для виконання RPC - виклику стандартної функції printf, а також головний модуль для тестування цих функцій.
Клієнт та сервер повинні спілкуватися за допомогою структури даних, яка передається по мережі. Накладіть розумні обмеження на довжину рядка, формату та число, типи та розміри змінних, які будуть приймати клієнтські сурогати.
Створення DEF-файла
Напишемо функцію для обчислення синуса:
double sin1(double x)
{
int ii; double xx,r,sl,f,delta=0.0001;
sl=x; ii=1; r=0; xx=x*x;
f= fabs(sl);
while (f>delta)
{
r=r+sl;
sl=-(sl*xx/(2*ii))/(2*ii+1);
f=fabs(sl);
ii=ii+1 ;
}
return(r);
}
Программа для тестування функції
unit SINTST;
interface
uses
Windows, Messages, SysUtils, Classes,Graphics, Controls, Forms,
Dialogs,
StdCtrls, Buttons, TeEngine, Series, ExtCtrls,
TeeProcs, Chart,a1;
type
TForm1 = class(TForm)
Chart1: TChart;
Series1: TFastLineSeries;
BitBtn1: TBitBtn;
procedure BitBtn1Click(Sender: TObject);
private
{ Private declarations }
public { Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
function sin1(x: Double): Double;
VAR I:INTEGER; R:DOUBLE;SL:DOUBLE;XX:DOUBLE;
CONST DELTA=0.0001 ;
begin
SL:=X; I:=1;
R:=0; XX:=X*X;
WHILE (ABS(SL)>DELTA) DO
BEGIN
R:=R+SL;
SL:=-(SL*XX/(2*I))/(2*I+1);
inc(i);
END;
result:=R;
end; {sin1}
procedure TForm1.BitBtn1Click(Sender: TObject);
VAR I:INTEGER;X:DOUBLE;Y:DOUBLE;
begin
FOR I:=1 TO 270 DO
BEGIN X:=0.1*I;
Y:=sin1(X);
CHART1.SERIES[0].ADDXY(X,Y,FLOATTOSTR(X),clwHITE);
END
end;
end.
Створення серверної частини (C/C++)
В результаті використання утиліти rpcmake.exe (або rpcmgui.exe) з парамерамі, відповідними вибору C або C++ як мова для сервера, отримаємо наступні файли: a1_c.c (stub-код, який можна вбудовувати в клієнтське застосування), a1_s.c (вихідний текст консольного застосування для сервера функціональності), a1_s.h - h-файл для myserv_s.c, a1.h - h-файл, що містить оголошення функцій без їх реалізації (використовується в клієнтському застосуванні). Реалізацію цих функцій (a1.c) слід створити розробнику. Код для сервера a1.с, сгенерований цією утилитою, виглядає наступним чином:
/*########################
# Server Proxy Procedure Code
# generated by rpcmake version2.0
# on Thursday, December 31, 1998 at 19:17:39
#
# interface: a1
#
########################
# server stub routines #
########################*/
#ifdef __mpexl
#include "dceinc.h"
#else
#include <dceinc.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
/* RPC stub and stub handle definitions */
void rpc_handle (char *, struct table *, int);
void rpc_sin1 (struct table *, int);
#ifdef __cplusplus
}
#endif
void rpc_sin1 (struct table *dce_table,int Socket)
{
double x;
int _i;
double sin1(double);
x = dce_pop_double(dce_table,"x");
dce_push_double(Socket,"dce_result",
sin1(x));
}
int main(int argc,char **argv)
{
char *ode_file = NULL,*ode_server = NULL;
char dce_func[VARLEN];
struct table *dce_table;
int called_init_func = 0;
int socket,rsocket;
if (!parse_args(&argc, argv,&ode_file)) {
printf ("Env flag (-e) not set\n");
ode_file = argc > 1 ? argv[argc-1] : (char *) NULL;
}
if (dce_setenv(ode_file,NULL,NULL) == 0) {
fprintf(stderr,"Set env %s failed\n", ode_file);
fprintf (stderr,"Reason: %s\n", dce_errstr());
exit(1);
}
ode_server = dce_servername("a1");
dce_checkver(2, 0);
if ((socket = dce_init_server( ode_file,ode_server)) <= 0) {
fprintf (stderr,"setup server failed\n");
fprintf (stderr,"Reason: %s\n", dce_errstr());
dce_set_exit();
}
while(1) {
dce_table = dce_waitfor_call(socket,dce_func);
if (dce_should_exit() ||
dce_err_is_fatal() )
{break;
}
else{
if (dce_server_is_ded()) {
dce_spawn(socket,argc,argv,ode_file,ode_server);
socket = dce_retsocket(); /* save for future */
}
rsocket = dce_retsocket(); /* (old socket closed) */
rpc_handle(dce_func,dce_table,rsocket);
dce_send(rsocket,dce_func);
dce_recv_conf(rsocket);
dce_release();
dce_table_destroy(dce_table);
if (!dce_server_is_ded()) {
dce_close_socket(rsocket);
}
}
}
dce_close_socket(rsocket);
dce_table_destroy(dce_table);
return(0);
}
void rpc_handle(char *func,struct table *dce_table,
int Socket)
{
if (strcmp(func,"sin1")==0)
(void)rpc_sin1(dce_table,Socket);
else (void)dce_unknown_func(func, dce_table, Socket);
}
H-файл a1_s.h виглядає наступним чином:
/*************************************
*
* Server Header for a1
* Generated by rpcmake version 3.0
* on Thursday, December 31, 1998 at 19:17:39
* **************************************/
#ifdef __cplusplus
extern "C" {
#endif
extern double sin1(double );
#ifdef __cplusplus
}
#endif
Код реалізації функції слід створити розробнику. Він повинен мати приблизно наступний вигляд:
USEUNIT("A1_s.c");
USELIB("odet30.lib");
//-----------------------------------------------------------------
double sin1(double x)
{
int ii; double xx,r,sl,f,delta=0.0001;
sl=x; ii=1; r=0; xx=x*x;
f= fabs(sl);
while (f>delta)
{
r=r+sl;
sl=-(sl*xx/(2*ii))/(2*ii+1);
f=fabs(sl);
ii=ii+1 ;
}
return(r);
}
Тестування серверу функціональності
Для тестування сервера потрібно створити для нього env-файл з описом змінних оточення:
DCE_BROKER=elmanova,16000
DCE_DEBUGLEVEL=DEBUG,DEBUG
DCE_LOG=server.log
Далі слід запустити Entera Broker( якщо він ще не запущений), створив перед цим конфігурований файл broker.env
start broker -e broker.env
Після цього слід створити і запустити командний файл для запуску сервера:
set odedir = c:\OpenEnv\Entera\TCP
start "IT IS A SERVER" a1_s -e server.env
Створення клієнтського оточення (C/C++)
Код, сгенерований утилітою rpcmake для клієнта C/C++ (a1_c.c), має наступний вигляд:
/*########################
# Client Proxy Procedure Code
# generated by rpcmake version 3.0
# on Thursday, December 31, 1998 at 19:17:39
#
# interface: a1
# */
#include <stdio.h>
#if defined __mpexl || defined _MACINTOSH_
#include "dceinc.h"
#else
#include <dceinc.h>
#endif
double sin1(double x)
{
double rv = 0; int Socket;
struct table *dce_table = NULL;
dce_checkver(2, 0);
if ((Socket = dce_findserver("a1")) >= 0) {
dce_push_double(Socket,"x",x);
dce_table = dce_submit("a1", "sin1", Socket);
}
rv = dce_pop_double(dce_table,"dce_result");
dce_table_destroy(dce_table);
return(rv);
}
H-файл для него має наступний вигляд:
**************************************/
*
* Client Header for a1
* Generated by rpcmake version 3.0
* on Thursday, December 31, 1998 at 19:17:39
* **************************************/
#ifdef __cplusplus
extern "C" {
#endif
extern double sin1(double );
#ifdef __cplusplus
}
#endif
Код клиентскої програми, в випадку С++Builder має наступний вигляд:
//-----------------------------------------
#include "dceinc.h"
#include "myserv.h"
USEUNIT("a1_c.c");
USELIB("odet30.lib");
//-----------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
dce_setenv("client.env",NULL,NULL); }
//---------------------------------------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender)
{
dce_release();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::BitBtn1Click(TObject *Sender)
{
int i; double x1,y;
for (i=1;i<271;i++)
{
x1=0.1*float(i);
y=sin1(x1);
Chart1->Series[0]->AddXY(x1,y,FloatToStr(x1),clWhite);
} }
//-----------------------------------------
Створимо обробник подій, який зв’язаний з натисненням кнопки CommandButton1 в документі (його прототип вже є в редакторі коду).
Private Sub CommandButton1_Click()
x = sin1#(0.25)
UserForm1.Label1.Caption = x
x = sin1#(0.5)
UserForm1.Label2.Caption = x
x = sin1#(0.75)
UserForm1.Label3.Caption = x
x = sin1#(1#)
UserForm1.Label4.Caption = x
x = sin1#(1.25)
UserForm1.Label5.Caption = x
x = sin1#(1.5)
UserForm1.Label6.Caption = x
x = sin1#(1.75)
UserForm1.Label7.Caption = x
x = sin1#(2#)
UserForm1.Label8.Caption = x
x = sin1#(2.25)
UserForm1.Label9.Caption = x
x = sin1#(2.5)
UserForm1.Label10.Caption = x
x = sin1#(2.75)
UserForm1.Label11.Caption = x
x = sin1#(3#)
UserForm1.Label12.Caption = x
UserForm1.Show
End Sub
Після обробника події додамо stub-код, що міститься у файлі a1_c, що згенерував.vb. І, нарешті, експортуємо в проект за допомогою пункту меню Файл/Експорт файлу модуль odet30.bas з комплекту постачання Entera. Створимо файл client.env у каталозі, що містить документ. Можливо, потрібно буде відредагувати приєднаний до проекту модуль, змінивши параметри процедури dce_setenv, вказавши дорогу до файлу client.env: rv = dce_setenv("client.env", "", "") Відзначимо, що бібліотека odet30.dll повинна бути доступною нашій програмі, так як із неї викликаються функції.