add directory study

This commit is contained in:
gohigh
2024-02-19 00:25:23 -05:00
parent b1306b38b1
commit f3774e2f8c
4001 changed files with 2285787 additions and 0 deletions

View File

@@ -0,0 +1,23 @@
CFLAGS=-F
all: client1 server1 client2 server2 client3 server3
client1: header.h client1.s
cc -o client1 client1.s
client2: header.h client2.s
cc -o client2 client2.s
client3: header.h client3.s
cc -o client3 client3.s
server1: header.h server1.s
cc -o server1 server1.s
chmem =1000 server1
server2: header.h server2.s
cc -o server2 server2.s
chmem =1000 server2
server3: header.h server3.s
cc -o server3 server3.s
chmem =1000 server3

View File

@@ -0,0 +1,59 @@
This directory contains several examples of networking code. These examples
also serve as programs to test the correctness and performance of the
networking and to provide some useful utility functions. In all the tests,
the client and server may run on the same machine, or if an Ethernet is
installed, on different machines. The ports 'xyz' used in tests 1 and 2
are examples. It is possible to run multiple tests at the same time (e.g.,
n1 sets of (client1, server1) and n2 sets of (client2, server2), provided
that each pair of (clientX, serverX) uses a port not used by any other process.
1. Test 1 consists of two programs, server1.c and client1.c. This test
transfers 1 megabyte from the client to the server in 1K chunks, has the
server transform the data and send it back. The client then verifies if
the returned data is correct. To run the test, type the following lines:
make client1 server1
server1 xyz &
client1 xyz
If an Ethernet is installed and the kernel has been compiled with
-DAM_KERNEL, the server and client may either be on the same machine or
one different ones. If there is no Ethernet and the kernel has been
compiled with _DAM_KERNEL -DNONET, both processes must be on the same CPU.
At the end of the test, "ok" is printed if no errors occurred. Otherwise
the number of bad transactions is printed. Both the client and server exit
by themselves after the test has been completed.
2. Test 2 consists of two programs, server2.c and client2.c. This test
measures the performance of the transactions. Like test 1, it can be run
either locally or remotely. The test consists of having the client request
n bytes of data from the server, where n grows from 1 to 30,000 bytes per
transaction. For each value of n, the test is run 1000 times to increase
the statistical accuracy. For each value of n, the value of n, the delay
(transaction time in milliseconds), and the throughput (bytes/sec moved)
is reported. To run the test, type:
make client2 server2
server2 xyz &
client2 xyz
3. Test 3 is an example of how one might go about making a remote file server
for MINIX to service diskless PCs. In this approach, one writes a server,
server3.c in this example, and a set of library routines, contained in
client3.c. These library routines should have the same names as the MINIX
system calls, such as open(), read(), and write(). When programs are linked
with these routines instead of the usual ones, the routines make calls to
the remote file server instead of FS. The file client3.c contains not only
a few of these library routines, but also a short main program to test them.
The main program fetches a file from the remote file server and copies it to
stdout. To test the program, type:
make client3 server3
server3 &
client3 <filename>
where <filename> is the name of a file on the same machine as server3. The
result of this command will be that <filename> is written to client3's
standard output.

View File

@@ -0,0 +1,56 @@
/* This program tests the basic RPC to see if it works. */
#include <amoeba.h>
#include "header.h"
#define MAX_TRIALS 1000
char buffer1[BUF_SIZE], buffer2[BUF_SIZE];
main(argc, argv)
int argc;
char *argv[];
{
header hdr1, hdr2;
int cnt, i, base = 0, size, errors, blocks, iterations = 0;
long bad_trans = 0;
if (argc != 2) {
printf("Usage: client1 portname\n");
exit(1);
}
/* Copy the filename into the start of the buffer. */
strncpy(&hdr1.h_port, argv[1], PORTSIZE);
hdr1.h_command = WORK;
printf("Number of tests performed = %5d ", 0);
while (iterations < MAX_TRIALS) {
/* Initialize the buffer. */
for (i = 0; i < BUF_SIZE; i++) buffer1[i] = base + i;
size = trans(&hdr1, buffer1, BUF_SIZE, &hdr2, buffer2, BUF_SIZE);
if (size < 0) {
printf("\nTransaction failed. Error = %d. ", size);
printf("Hit F1 to see if AMTASK running.\n");
exit(1);
}
/* Check reply. */
errors = 0;
for (i = 0; i < BUF_SIZE; i++)
if ( (buffer2[i]&0377) != ( (buffer1[i]+1)&0377)) errors++;
if (errors > 0) bad_trans++;
blocks++;
base++;
iterations++;
if (iterations % 10 == 0) printf("\b\b\b\b\b\b%5d ", iterations);
}
/* Test done. Send null trans to tell server. Report on errors. */
hdr1.h_command = QUIT;
trans(&hdr1, buffer1, 0, &hdr2, buffer2, BUF_SIZE);
printf("\b. Number of errors = %d.\n", bad_trans);
}

View File

@@ -0,0 +1,76 @@
/* This file is the client of a test program for measuring RPC speed. */
#include <amoeba.h>
#include <minix/callnr.h>
#include "header.h"
#define TRIALS 1000
char buffer[MAX_TRANS];
int bytes[] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096,
8192, 16384, 30000, 0};
header hdr1, hdr2;
main(argc, argv)
int argc;
char *argv[];
{
int i, cnt;
if (argc != 2) {
printf("Usage: client2 portname\n");
exit(1);
}
/* Copy the filename into the start of the buffer. */
strncpy(&hdr1.h_port, argv[1], PORTSIZE);
hdr1.h_command = READ;
printf("Buf size Delay Throughput (Each test repeated %d times)\n", TRIALS);
printf(" (msec/trans) (bytes/sec)\n");
printf("-------- ------------ -----------\n");
i = 0;
while (bytes[i] != 0) {
run_test(bytes[i], TRIALS);
i++;
}
hdr1.h_command = QUIT;
trans(&hdr1, buffer, 0, &hdr2, buffer, 0);
exit(0);
}
run_test(count, trials)
int count, trials;
{
/* Run a performance test. */
int i, n;
long start, finish, traffic, sec, msec, delay, throughput;
time(&start); /* record starting time */
for (i = 0; i < trials; i++) {
hdr1.h_command = READ;
hdr1.h_size = (unshort) count;
n = trans(&hdr1, buffer, 0, &hdr2, buffer, MAX_TRANS);
if (n < 0) {
printf("Transaction failed. Error = %d. ", n);
printf("Hit F1 to see if AMTASK running.\n");
exit(1);
}
}
time(&finish);
sec = finish - start; /* time for this trial in seconds */
msec = 1000L * sec;
traffic = (long) trials * (long) count;
delay = msec/trials; /* msec per transaction */
if (sec != 0L)
throughput = traffic/sec;
else
throughput = 0L;
printf(" %5d %4D %7D\n", count, delay, throughput);
}

View File

@@ -0,0 +1,236 @@
/* This file shows how one could build a remote file server for MINIX.
* In this file there are several library routines for the basic system
* calls. Unlike the "real" ones, these call a remote file server instead
* of the local kernel. On client machines, one would replace the library
* routines with these routines, and then recompile programs. In this way,
* clients will then call the remote file server. It should be obvious that
* this file is just an example, and that a productio version would have to
* be much more complete.
*
* The file server3.c contains the start of a stateless file server. Because
* MINIX is not stateless, the conversion must be done in this library. For
* example, when an open() is done, the library records the name, but no
* operation is performed on the file server.
*
* An alternative approach to making a remote file systems is to replace FS,
* the local file server, with one that makes the calls to the remote file
* server itself. This approach is less efficient, because a call then
* consists of a local FS call plus a remote one, but it is more transparent
* because no programs need to recompiled.
*/
#include <amoeba.h>
#include <errno.h>
#include <minix/callnr.h>
#include "header.h"
#define MAX_FD 20
#define LOCAL 100
#define HEAPSIZE 512 /* space for file names */
#define WRITING 2
#define ER -1
#define FS 1
#define NIL_PTR (char*) 0
/* The local array is indexed by file descriptor. Those entries containing
* LOCAL are local (e.g., stdin), those containing REMOTE are remote, and
* those containing 0 are unassigned.
*/
char where[MAX_FD] = {LOCAL, LOCAL, LOCAL};
long pos[MAX_FD]; /* current offset */
char *server_name = "filsrv";
char *file_name[MAX_FD];
char heap[HEAPSIZE];
char *heap_ptr = heap;
header hdr1, hdr2;
char buffer[BUF_SIZE+NAME_SIZE];
extern int errno;
/*============================= Remote Library ==============================*/
int open(name, how)
char *name;
int how;
{
/* Open is entirely local. */
int i, len;
if (how < 0 || how > 2) { errno = EINVAL; return(ER);}
/* Find a free file descriptor. */
for (i = 0; i < MAX_FD; i++) {
if (where[i] == 0) {
len = strlen(name);
file_name[i] = heap_ptr;
bcopy(name, heap_ptr, len);
heap_ptr += len;
*heap_ptr++ = 0;
where[i] = how+1;
return(i);
}
}
errno = EMFILE;
return(ER);
}
int creat(name, mode)
char *name;
int mode;
{
/* Create a file. */
int i, len, n;
/* Find a free file descriptor. */
for (i = 0; i < MAX_FD; i++) {
if (where[i] == 0) {
len = strlen(name);
file_name[i] = heap_ptr;
bcopy(name, heap_ptr, len);
heap_ptr += len;
*heap_ptr++ = 0;
where[i] = WRITING;
strncpy(&hdr1.h_port, server_name, PORTSIZE);
hdr1.h_command = CREAT;
hdr1.h_size = mode;
n = trans(&hdr1, file_name[i], len+1, &hdr2, buffer, 0);
if (n < 0) {errno = EIO; return(ER);}
return(hdr2.h_status);
}
}
errno = EMFILE;
return(ER);
}
/* int close(fd)
int fd;
{
if (where[fd] == LOCAL) return(Xclose(fd));
if (where[fd] == 0) {errno = EBADF; return(ER);}
where[fd] = 0;
return(OK);
}
*/
int read(fd, buf, bytes)
int fd, bytes;
char buf[];
{
/* Primitive read() routine for reads up to 1K. */
int n;
if (where[fd] == LOCAL) return (Xread(fd, buf, bytes));
if ((where[fd]&1) == 0) {errno = EBADF; return(ER);}
if (bytes > BUF_SIZE) return(EINVAL); /* in a real version, fix this */
strncpy(&hdr1.h_port, server_name, PORTSIZE);
hdr1.h_command = READ;
hdr1.h_size = bytes;
hdr1.h_offset = pos[fd];
n = trans(&hdr1, file_name[fd], strlen(file_name[fd])+1, &hdr2, buf, bytes);
if (n < 0) {errno = EIO; return(ER);}
if (hdr2.h_extra != 0) errno = hdr2.h_extra;
pos[fd] += hdr2.h_status; /* advance file position */
return(hdr2.h_status);
}
int write(fd, buf, bytes)
int fd, bytes;
char buf[];
{
/* Primitive write() routine for writes up to 1K. This is a very simple
* routine. Because the server is stateless, for a write we must send both
* the data and the file name. In this example, the first 1K of the buffer
* is reserved for the data, with the file name starting at position 1024.
*/
int n, len;
if (where[fd] == LOCAL) return (Xwrite(fd, buf, bytes));
if ((where[fd]&02) == 0) {errno = EBADF; return(ER);}
if (bytes > BUF_SIZE) return(EINVAL); /* in a real version, fix this */
strncpy(&hdr1.h_port, server_name, PORTSIZE);
len = strlen(file_name[fd]);
hdr1.h_command = WRITE;
hdr1.h_size = bytes;
hdr1.h_offset = pos[fd];
bcopy(buf, buffer, bytes); /* copy data to message */
bcopy(file_name[fd], &buffer[BUF_SIZE], len+1);
n = trans(&hdr1, buffer, BUF_SIZE+len+1, &hdr2, buf, 0);
if(n < 0) {errno = EIO; return(ER);}
if (hdr2.h_extra != 0) errno = hdr2.h_extra;
pos[fd] += hdr2.h_status;
return(hdr2.h_status);
}
/* Below are the real calls, which are sometimes needed. */
int Xread(fd, buffer, nbytes)
int fd;
char *buffer;
int nbytes;
{
int n;
n = callm1(FS, READ, fd, nbytes, 0, buffer, NIL_PTR, NIL_PTR);
return(n);
}
int Xwrite(fd, buffer, nbytes)
char *buffer;
int nbytes;
{
return callm1(FS, WRITE, fd, nbytes, 0, buffer, NIL_PTR, NIL_PTR);
}
int Xclose(fd)
int fd;
{
return callm1(FS, CLOSE, fd, 0, 0, NIL_PTR, NIL_PTR, NIL_PTR);
}
/* ========================= test program =============================*/
main(argc, argv)
int argc;
char *argv[];
{
int fd1, n;
char b[1024];
if (argc != 2) {
printf("Usage: client3 file\n");
exit(1);
}
fd1 = open(argv[1], 0);
if (fd1 < 0) {
printf("Open of %s failed\n", argv[1]);
exit(1);
}
do {
if ((n=read(fd1, b, 1024) < 0)) {
printf("Cannot read %s\n", argv[1]);
exit(1);
}
if (write(1, b, n) < 0) {
printf("Cannot write stdout\n");
exit(1);
}
} while (n > 0);
}

View File

@@ -0,0 +1,11 @@
/* Some declarations need by the example clients and servers. */
char *file_server = "filsrv";
#define BUF_SIZE 1024
#define NAME_SIZE 512
#define WORK 1
#define QUIT 999
#define MAX_TRANS 30000

View File

@@ -0,0 +1,44 @@
#include <amoeba.h>
#include "header.h"
char buffer[BUF_SIZE];
main(argc, argv)
int argc;
char *argv[];
{
unshort getreq(), putrep();
header hdr;
int cnt, i, iterations = 0;
if (argc != 2) {
printf("Usage: server1 portname\n");
exit(1);
}
strncpy( (char *) &hdr.h_port, argv[1], PORTSIZE); /* init port */
while (1) {
/* Wait for a request to arrive. */
if ((cnt = (short) getreq(&hdr, buffer, BUF_SIZE)) < 0) {
printf("Server's getreq failed. Error = %d. ", cnt);
printf("Hit F1 to see if AMTASK running.\n");
exit(1);
}
/* Opcode QUIT indicates that we are done. */
if (hdr.h_command == QUIT) {
putrep(&hdr, buffer, 0);
exit(0);
}
/* We have a request. Increment each byte. */
for (i = 0; i < cnt; i++) buffer[i]++;
/* Send back reply. */
hdr.h_status = 0;
putrep(&hdr, buffer, cnt);
}
}

View File

@@ -0,0 +1,40 @@
#include <amoeba.h>
#include "header.h"
char buffer[MAX_TRANS];
main(argc, argv)
int argc;
char *argv[];
{
header hdr;
int count;
if (argc != 2) {
printf("Usage: server2 portname\n");
exit(1);
}
strncpy( (char *) &hdr.h_port, argv[1], PORTSIZE); /* init port */
while (1) {
/* Wait for a request to arrive. */
count = (short) getreq(&hdr, buffer, MAX_TRANS);
if (count < 0) {
printf("Server's getreq failed. Error = %d. ", count);
printf("Hit F1 to see if AMTASK running.\n");
exit(1);
}
/* Opcode QUIT indicates that we are done. */
if (hdr.h_command == QUIT) {
putrep(&hdr, buffer, 0);
exit(0);
}
/* We have a request. Reply. */
count = hdr.h_size;
putrep(&hdr, buffer, count);
}
}

View File

@@ -0,0 +1,104 @@
#include <amoeba.h>
#include <minix/callnr.h>
#include <errno.h>
#include "header.h"
header hdr; /* header for incoming messages */
char buffer[BUF_SIZE+NAME_SIZE]; /* buffer for incoming messages */
char *server_name = "filsrv";
int repsize;
extern int errno;
main()
{
/* This is a primitive file server. The client runs with a special set of
* routines for read(), write(), etc. that call this server. The server is
* stateless.
*/
int s;
int count;
unshort opcode, size;
strncpy( (char *) &hdr.h_port, server_name, PORTSIZE); /* init port */
while (1) {
/* Wait for a request to arrive. */
count = (short) getreq(&hdr, buffer, MAX_TRANS);
if (count < 0) {
printf("Server's getreq failed. Error = %d. ", count);
printf("Hit F1 to see if AMTASK running.\n");
exit(1);
}
/* Dispatch on opcode. */
opcode = hdr.h_command;
repsize = 0;
errno = 0;
switch(opcode) {
case CREAT: s = do_creat(); break;
case READ: s = do_read(); break;
case WRITE: s = do_write(); break;
default: s = EINVAL; break;
}
/* Work done. Send a reply. */
hdr.h_status = (unshort) s;
hdr.h_extra = (unshort) errno;
putrep(&hdr, buffer, repsize);
}
}
int do_read()
{
/* Stateless read. */
int fd, n;
long offset;
unshort count;
offset = hdr.h_offset;
count = hdr.h_size;
if (count > MAX_TRANS) count = MAX_TRANS;
fd = open(buffer, 0); /* open the file for reading */
if (fd < 0) return(errno);
lseek(fd, offset, 0);
n = read(fd, buffer, count);
close(fd);
repsize = n;
return(n);
}
int do_write()
{
/* Stateless write. */
int fd, n;
long offset;
unshort count;
offset = hdr.h_offset;
count = hdr.h_size;
if (count > MAX_TRANS) count = MAX_TRANS;
fd = open(&buffer[BUF_SIZE], 2); /* open the file for writing */
if (fd < 0) return(errno);
lseek(fd, offset, 0);
n = write(fd, buffer, count);
close(fd);
return(n);
}
int do_creat()
{
/* Stateless creat. */
int fd, n, mode;
mode = hdr.h_size;
fd = creat(buffer, mode); /* creat the file */
close(fd);
return(fd);
}