Cache Consistency Distributed Application
Design and write an application that maintains a consistent replicated
cache. Each instance of the application will maintain a replicated
cache of information, such that each instance of the applications
cache is identical. One may run many instances of the application and
thus have many instances of the replicated and consistent cache. This
project requires one to create an application that receives messages
and places them in a cache (memory). It also requires that one write
an application that generates cache entries and sends them to each
instance of the application.
The application must be able to display the cache on the screen (a
console application is fine) so that we can check for cache
consistency. When a new message arrives from the data generating
application, the information is to be added to the cache.
Start-up Issues
If a new instance of the application is started after several
instances of the application have already been started and their
caches already contain data, the new instance of the application must
receive the latest cache information from a neighbor application
instance, so as to become caught up with the latest cache information.
After which, the new instance may receive cache updates from the data
generating application.
Thus, this project deals with establishing socket communications
between a data generating application and each instance of the caching
application, maintaining cache consistency amongst the different
instances of the applications, and recovering/initializing the cache
from other instances of the caching applications upon startup.
The kind of information you place in the cache is totally up to you.
Also, you may consider assigning sequence numbers with each cache
update, so as to aid one in cache synchronization. You may implement
this project in any language of choice.
Here are some socket web site
http://www.ecst.csuchico.edu/~beej/guide/net/
http://www.sockets.com/
http://www.javaworld.com/javaworld/jw-12-1996/jw-12-sockets.html
http://www.cisco.com/univercd/cc/td/doc/product/software/ios112/ios112p/gsr/wred_gs.htm#xtocid0
I prefer to use C++ to write the programming (please comment you code)
and need document describing the objective, design and implementation
of your project. Any issues, lessons learned, obstacles overcome
should be noted. I need them as soon as possible. The latest time is
April 30. |
Request for Question Clarification by
maniac-ga
on
08 Apr 2003 17:14 PDT
Hello Questionboy,
This is a very interesting application. There appear to be a few
inconsistencies in the description of the application. Could you
clarify these points for me?
- The first section implies a single application. The fourth implies
at least two (data generation, caching) applications. Please confirm
which is correct. I'll assume two for now. I'll also assume a single
data generator and one or more caching applications are active.
- The second section implies display of data. I'll assume that both
the data generator and cache applications will do this. [or should
this be a third application, reading from the cache?]
- The third section implies a discovery process. The simplest way is
to tell the cache application where to contact the data generator (or
cache application). Is this good enough or must the cache find the
data generator automatically? In the latter case, this could be done
using a broadcast or IP multicast message. Using IP multicast may
require a special setting on your computer and/or network; will you
need instruction on setting this up if used?
- The use of sockets generally implies use of a Unix compatible
system, standard header files, etc. Is this for Linux, Unix, or for
something else? I'll also assume the use of gcc as the C/C++ compiler
as well.
- I'll assume a client / server model. The data generator is the
"server", each cache is a "client". Once the cache application
locates the server - it gets a message indicating where to get the
initial updates, pulls data from that cache, & then monitors messages
from the server.
- The server maintains a list of active links & sends each update to
all of them. Errors when sending a message to a cache client will
result in dropping that client.
- For initial testing, you can run using the "local host" and not
require the use of two or more machines. The final tests must be done
with at least three machines. Please confirm.
- Based on these clarifications, I'll get you an estimate of how long
it will take to produce this application and can proceed from there.
--Maniac
|
Clarification of Question by
questionboy-ga
on
08 Apr 2003 22:03 PDT
-One single data generator and one or more caching appicatjions are
active.
-Both the data ganerator and cache applications will do the display of
data.
-The new instance of the aplication must receive the latest cache
information from a neighbor application instance. This can be done
using IP multicast message.I will certainly need the instruction of
setting up my computer.
-C++ compiler
|
Request for Question Clarification by
maniac-ga
on
09 Apr 2003 17:44 PDT
Hello Questionboy,
Thanks for the clarification. Let me provide an initial set of files
for you to try on your system to confirm basic operations work OK.
See below for
- dapp.h - header file for the two applications, shared data types
- dcache.c - data cache (client) application
- dgen.c - data generation (server) application
- Makefile - to automate the build of the application
Currently written in C; the system calls are all C functions and I
don't see any specific need for templates or objects from C++.
Currently built using gcc and tested on a FreeBSD system but should
also run on Linux w/o any problems.
Put the files into the same directory and use
make
to build the applications (dcache and dgen).
To test on a single system, in one window...
./dcache localhost
and you will get a repeating warning message that the data generator
is not yet running (ECONNREFUSED) and that it will retry in 10
seconds. In another window
./dgen
and in a few seconds, both programs will connect and exit without any
further messages. If you run dgen before dcache, both applications
should exit w/o any messages. If you have two systems, change the
argument for dcache to the host name that is running dgen.
If this works OK on your system - the rest of the application is
straight forward and should take a day or so to complete. If you have
suggestions on the type of data to exchange - let me know. Otherwise,
data generation will be a sequence number, "slot number", and the
current time of day. The display will be the number and time of day in
each slot (say 10 slots). Something that can be updated say once per
second to see progress.
If it does not work OK on your system - I will need the specific error
messages, compiler errors, and your system configuration (e.g, OS, CPU
type) to help diagnose the problem. Every system call should have a
call to status to help diagnose the problem.
--Maniac
-- dapp.h --
/*
* dapp.h -- header file for distributed generator / cache application
*/
#ifndef __DAPP
/* TCP port number to use */
#define DPORT 2525
#define __DAPP
#endif
-- dcache.c --
/*
* dcache.c -- distributed cache application
*/
/* system includes */
#include <stdlib.h>
#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include "dapp.h"
static char *pname; /* name of this application */
static int flag_tcp = 0; /* link connected if non zero */
static int my_socket = 0; /* socket connection */
static int my_port = DPORT; /* tcp port connection */
static u_int32_t remote_addr = 0; /* address of remote host */
/*************************************************************
* helper to dump error messages
* pass retval back for use in if statement
*************************************************************/
int status(int retval,
char *level,
char *what,
char *where)
{
if (retval)
{
fprintf(stderr, "%s: %s - %s failed in %s\n",
pname, level, what, where);
perror(pname);
}
return retval;
}
/*************************************************************
* clean up the application
*************************************************************/
void cleanup()
{
}
/*************************************************************
* establish the socket connection
*************************************************************/
void init_socket()
{
int retval;
struct sockaddr_in my_sockdata;
int socket_tos = IPTOS_LOWDELAY; /* request minimial delays */
const int conn_delay = 10;
while (1)
{
my_socket = socket(PF_INET, SOCK_STREAM, 0);
retval = (my_socket < 0);
if (status(retval, "ERROR", "socket", "init_socket"))
exit(EXIT_FAILURE);
/* establish the connection */
bzero ((char *)&my_sockdata, sizeof(my_sockdata));
my_sockdata.sin_family = AF_INET;
my_sockdata.sin_port = htons(my_port);
my_sockdata.sin_addr.s_addr = remote_addr;
retval = connect(my_socket, (struct sockaddr*) &my_sockdata,
sizeof(my_sockdata));
if (retval == 0)
break; /* success */
else if (errno == ECONNREFUSED)
{
close(my_socket); /* socket unusable - close it */
fprintf(stderr, "%s: STATUS - ECONNREFUSED, retry in %d
seconds.\n",
pname, conn_delay);
sleep(conn_delay);
}
else
{
status (retval, "ERROR", "connect", "init_socket");
exit(EXIT_FAILURE);
}
}
/*
* connection succeeded, set socket options
*/
retval = setsockopt (my_socket, IPPROTO_IP, IP_TOS,
&socket_tos, sizeof(socket_tos));
status (retval, "WARNING", "setsockopt", "init_socket");
/* prefer this, but not fatal */
flag_tcp++; /* note connection established */
}
/*************************************************************
* initialize the application
* register the exit procedure
* handle command line arguments
* get the socket
*************************************************************/
void initialize(int argc,
char *argv[])
{
int retval;
struct hostent *remote_host;
if (status(atexit(cleanup), "ERROR", "atexit", "initialize"))
exit(EXIT_FAILURE);
/* capture program name */
pname = argv[0];
/* get address of remote host */
if (status((argc <= 1), "ERROR", "argc > 1", "initialize"))
exit(EXIT_FAILURE);
remote_host = gethostbyname(argv[1]);
retval = (remote_host == (void *) 0);
if (status(retval, "ERROR", "gethostbyname", "initialize"))
exit(EXIT_FAILURE);
retval = (remote_host->h_length > sizeof(remote_addr));
if (status(retval, "ERROR", "remote address fits", "initialize"))
exit(EXIT_FAILURE);
retval = (remote_host->h_addr_list[0] == (void *)0);
if (status(retval, "ERROR", "remote address valid", "initialize"))
exit(EXIT_FAILURE);
memcpy(&remote_addr, remote_host->h_addr_list[0],
remote_host->h_length);
init_socket();
}
/*************************************************************
* main program
*************************************************************/
int main (int argc,
char * argv[])
{
initialize(argc, argv);
return EXIT_SUCCESS;
}
-- dgen.c --
/*
* dgen.c -- distributed data generator
*/
/* system includes */
#include <stdlib.h>
#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include "dapp.h"
static char *pname; /* name of this application */
static int my_port = DPORT; /* tcp port connection */
static int flag_conn = 0; /* have connection socket */
static int conn_socket = 0; /* connection socket number */
/*************************************************************
* helper to dump error messages
* pass retval back for use in if statement
*************************************************************/
int status(int retval,
char *level,
char *what,
char *where)
{
if (retval)
{
fprintf(stderr, "%s: %s - %s failed in %s\n",
pname, level, what, where);
perror(pname);
}
return retval;
}
/*************************************************************
* clean up the application
*************************************************************/
void cleanup()
{
if (flag_conn)
(void)close(conn_socket); /* ignore errors */
}
/*************************************************************
* establish the socket connection
*************************************************************/
void init_socket()
{
struct sockaddr_in my_sockdata;
int my_sockdata_len = sizeof(my_sockdata);
int retval;
int cache_socket = 0;
conn_socket = socket(PF_INET, SOCK_STREAM, 0);
if (status((conn_socket < 0), "ERROR", "socket", "init_socket"))
exit(EXIT_FAILURE);
flag_conn++;
bzero ((char *)&my_sockdata, sizeof(my_sockdata));
my_sockdata.sin_family = AF_INET;
my_sockdata.sin_port = htons(my_port);
my_sockdata.sin_addr.s_addr = htonl(INADDR_ANY);
retval = bind (conn_socket, (struct sockaddr*) &my_sockdata,
sizeof(my_sockdata));
if (status(retval, "ERROR", "bind", "init_socket"))
exit(EXIT_FAILURE);
retval = listen (conn_socket, 1); /* listen for one at a time */
if (status(retval, "ERROR", "listen", "init_socket"))
exit(EXIT_FAILURE);
/* this will block - don't bother with data generation until
* we have a cache reading application */
cache_socket = accept (conn_socket, (struct sockaddr*) &my_sockdata,
&my_sockdata_len);
retval = (cache_socket < 0);
if (status(retval, "ERROR", "accept", "init_socket"))
exit(EXIT_FAILURE);
}
/*************************************************************
* initialize the application
* register the exit procedure
* handle command line arguments
* get the socket
*************************************************************/
void initialize(int argc,
char *argv[])
{
if (status(atexit(cleanup), "ERROR", "atexit", "initialize"))
exit(EXIT_FAILURE);
/* capture program name */
pname = argv[0];
init_socket();
}
int main (int argc,
char * argv[])
{
initialize(argc, argv);
return EXIT_SUCCESS;
}
-- Makefile --
CFLAGS=-g -O2 -Wall
all : dgen dcache
dgen.o : dgen.c dapp.h
dgen : dgen.o
dcache.o : dcache.c dapp.h
dcache : dcache.o
|
Clarification of Question by
questionboy-ga
on
10 Apr 2003 13:46 PDT
Hello Maniac
Thanks for your help. I compile this programming, and then the
compiler shows me that there are two errors: fatal error C1083: Cannot
open include file: 'netdb.h': No such file or directory and another is
same error.
I show you how I do (I use Microsoft Visual Studio C++ 60):
-open new file(project) and then select Win32 Application
-open new file(file) and the select C/C++ Header file. Create dapp.h
-open new file(file) and the select C++ Source file. Create dcache.c
-open new file(file) and the select C++ Source file. Create dgen.c
-open new file(file) and the select Text file. Create makefile
I think those steps maybe are wrong. Can you show me how to do it.
my system configuration: Windows 2000, pentium 3, 128 RAM, only have
Microsoft Visual Studio C++ 60 and jBuilder 4
I really appreciate your patience.
--questionboy
|
Request for Question Clarification by
maniac-ga
on
10 Apr 2003 15:43 PDT
Hello Questionboy,
As I mentioned in the original request for clarification, I assumed
use of a Unix compatible system. The reason you are getting the errors
is that one or more of the header files does not exist. For example,
the function gethostbyname is defined in netdb.h on Unix systems.
You can download that kind of software for Microsoft Windows from
http://cygwin.com/
it may also be necessary to download compatible development tools
(e.g., gcc, gdb) from
http://cygwin.com/packages/
If you don't want to pursue this (or have access to a Linux system),
I'll stop working on this and let someone else answer your question.
--Maniac
|
Clarification of Question by
questionboy-ga
on
10 Apr 2003 19:24 PDT
Hello Maniac
I download the Cygwin Bash Shell from http://cygwin.com/
but I don't know how to download gcc and gdb from
http://cygwin.com/packages/
so can you tell me exactly what kind of stuff that I require. In my
computer, O.S. is Windows 2000 and only have Microsoft Visual Studio
C++ 6.0 and jBuilder 4 software.
I have a questin. Does this problem have to use Linux or Unix? Thanks.
|
Request for Question Clarification by
maniac-ga
on
11 Apr 2003 05:03 PDT
Hello Questionboy,
To answer your two questions:
- how to download gcc, gdb, etc?
According to
http://cygwin.com/
it states you run the setup program and then select the categories &
packages desired. Your system will download the appropriate software
and install it. If it is not obvious which selections are appropriate
- I can try to do that step on a Windows NT system later today to
suggest which ones.
- does this program require Unix / Linux?
No, but I have access to a complete set of software development tools
on Unix and don't on a Windows PC. We could probably work to produce
an application that builds OK in Visual Studio but that would require
a lot of work on your part (e.g., to research the proper header files
/ libraries or DLL's).
Let me know how you want to proceed.
--Maniac
|
Request for Question Clarification by
maniac-ga
on
11 Apr 2003 09:17 PDT
Hello Questionboy,
To follow up, I did the following steps on an NT system:
- downloaded the cygwin set up program
- ran set up & accepted the defaults
[this loaded the basic applications - archive.progeny.com seems to be
a fast mirror site]
- ran set up again & selected gcc, gdb, and make
[downloaded the key development tools - took a few minutes on a fast
line]
- created the four files in a directory
- ran a cygwin bash shell and used cd to change to that directory
example - cd /cygdrive/d/google/dnet
- ran make
make
[a few messages were printed, no errors]
- ran a second cygwin bash shell, used cd to change to that directory
- ran ./dcache in one window, ./dgen in the other
[the programs ran as expected, though I got a warning about an invalid
option in setsockopt; this is not fatal & I'll likely remove that call
since it may not be supported on MS windows]
--Maniac
|
Clarification of Question by
questionboy-ga
on
11 Apr 2003 16:25 PDT
Hello Maniac
I spent a lot of time to download the cygwin set up program,
gcc-3.2-3-src.tar.bz2, gcc-3.2-3.tar.bz2, gbd(2 files) and, make(2
files)from archive.progeny.com because I use dial-up Internet.
After, I tried your steps,
but I didn't understand what you meant
-ran set up again & selected gcc, gdb, and make [how to select?]
-created the four files in a directory [I guest the 4 files are
dapp.h, dcache.c, dgen.c and Makefile, but where I should create
to?]
-ran a cygwin bash shell and used cd to change to that directory [I
tried many times but it couldn't find the file. e.g. I wanted to
reach the cygwin file, I typed cd/cygwin it show me "No such file
or directory" but I tried in DOS, I typed cd cygwin it worked.
Became D:\cygwin> ]
-ran make [how to run it?]
I wonder if I compile the program on another computer(Windows XP and
the same C++compiler), I still have to do the steps as I did on my
computer?
|
Clarification of Question by
questionboy-ga
on
12 Apr 2003 12:09 PDT
Hello Maniac
Sorry about occupying your time. Can you post the Zip file containing
the code and other stuff that I need? Thanks a lot. Also, is it
possible for me to communicate with you on MSN or ICQ when I get a
small problem about this question because I don't need to wait the
answer until tomorrow.
|
Request for Question Clarification by
maniac-ga
on
14 Apr 2003 15:11 PDT
Hello Questionboy,
Two clarifications, let me address them in order.
I am not quite sure from your description if you have the development
tools installed properly or not. From the cygwin shell, try
which gcc
as a result of this command you should get
/usr/bin/gcc
If you get this, skip the rest of this paragraph. If not, run the
setup program again for cygwin, select Install from Local Directory,
(the next few pages should have the correct defaults from before),
click on the + sign next to devel, then click on the circular loop
symbol next to the packages to install until they indicate "install"
(the other choices might be skip, keep, or deinstall). As I mentioned
before, there are some dependent packages that may also have to be
downloaded - that was why I recommended "Install from Internet" in a
previous message. When done, repeat the above command - if it works,
proceed; if not try Install from Internet.
Where to put the source files? In any directory you like. I created
two directories on my D drive. The first named google, the second
inside it named dgen. From a DOS window, the path would be something
like:
D:\google\dgen
From the bash window, the path will be
/cygdrive/d/google/dgen
The command to change to that directory in the cygwin shell is
cd /cygdrive/d/google/dgen
using the "change directory" command (cd). [each command ends w/ the
enter key] You can view the directory with the explorer or any other
utility program. If the four files (Makefile, dapp.h, dgen.c,
dcache.c), you can then enter
make
in the cygwin shell window and it should result in the following
output
gcc -g -O2 -Wall -c -o dgen.o dgen.c
gcc dgen.o -o dgen
gcc -g -O2 -Wall -c -o dcache.o dcache.c
gcc dcache.o -o dcache
(no warnings or error messages, both applications are built).
To run the application on another computer, you need:
- the cygwin shell (just the defaults from setup)
- the executable programs
you should not need the compiler nor any of the other development
tools. If you have file sharing turned on, I'd use that to move the
files instead of rebuilding them on each machine (unless you want to).
About posting a zip file with what you need - I don't have the
facilities to do that. The source code will be part of the answer, but
the other stuff (e.g., development tools) would have to be installed
on your system anyway.
About using MSN or ICQ - I can't post an email address nor other
personal contact information here. This is a restriction described in:
https://answers.google.com/answers/researcherguidelines.html#requirements
(see sub item #3). Sorry. I will suggest that Google add some form of
chat or similar method to exchange data more quickly but until then I
will try to check the status of the question more frequently.
--Maniac
|
Clarification of Question by
questionboy-ga
on
22 Apr 2003 22:10 PDT
Hello Maniac
I tried those steps again, but it still could not work. I will ask my
friend how to run your program.
anyway, I wonder if you have finished this program because I need it
as soon as possible.
|
Request for Question Clarification by
maniac-ga
on
23 Apr 2003 16:00 PDT
Hello Questionboy,
I am uncomfortable writing this program and making you pay for it if
you can't run it. As an alternative, I could try writing it in Java -
but you may get the same problem with different tools. Please advise.
--Maniac
|
Clarification of Question by
questionboy-ga
on
23 Apr 2003 22:37 PDT
Hello Maniac
I think which language that is comfortable for you to write the
program, and I will pursue yours. However, you need to tell me what
tool is required, and then I will do it at my friend's home if I can't
run it in my computer.
|
Request for Question Clarification by
maniac-ga
on
24 Apr 2003 05:24 PDT
Hello Questionboy,
See below, the stub caching program rewritten in Java. The steps I
used to build / run it were:
[build w/ Java system, producing jdnet.jar]
java -jar jdnet.jar jdnet localhost
the output was:
jdnet: STATUS - I/O error, retry soon failed in main
repeated until I ran the C data generator, when it output:
Hello World!
java has exited with status 0.
If you can repeat this (or something similar for your Java development
system), I will continue in Java. If not, I will continue in C.
--Maniac
jdnet.java follows
//
// jdnet.java
// jdnet
import java.util.*;
import java.io.*;
import java.net.*;
public class jdnet {
static String pName;
static int portNo = 2525;
static int delayFor = 10000; // 10 second wait (in milliseconds)
static Socket mySocket;
private static boolean status(boolean retVal,
String level,
String what,
String where) {
if (retVal) {
System.err.println(pName + ": " + level + " - " +
what + " failed in " + where);
}
return retVal;
}
public static void main (String args[]) {
// insert code here...
pName = args[0];
if (status((args.length <= 1), "ERROR", "no args", "main"))
System.exit(1);
do {
try {
mySocket = new Socket(args[1], portNo);
} catch (UnknownHostException e) {
status(true, "ERROR", "unknown host", "main");
System.exit(1);
} catch (IOException e) {
status(true, "STATUS", "I/O error, retry soon",
"main");
try {
Thread.currentThread().sleep(delayFor);
} catch (InterruptedException f) {
status(true, "STATUS", "wait interrupted",
"main");
}
}
} while (mySocket == null);
System.out.println("Hello World!");
}
}
|
Clarification of Question by
questionboy-ga
on
29 Apr 2003 23:24 PDT
Hello Maniac
I still have problems of running the source code. Since the project is
due next Wednesday that I am really running out of time, I eventually
came up with the following options.
1)Since I am not able to run it, I have no idea of how I am going
complete the project, and it is definately impossible to "paste" the
code on Words. Therefore, I need you to run it successfully and have
the folder well-organized.
This is why I asked you if you can provide me a link so that I will be
able to download it.(since you cannot send it to me by e-mail or any
other way.)
2) If you really can't take option 1, my question will be--can I use
the Visual Studio C++ 6.0 to run the code of C you gave me before with
the Unix system?If "YES", I will still run it with the Visual Studio
C++ 6.0 but without Unix system (because I don't have it), but I will
just ignore the "errors".
Thank you very much.
|
Request for Question Clarification by
maniac-ga
on
30 Apr 2003 05:04 PDT
Hello Questionboy,
In regards to #2 (build with Visual C++). You can't *ignore* the
errors - you won't have a program that works. If you want to build
this application with Visual C++, I need the following information:
- what are the *exact* error messages when you build the two
applications (dgen, dcache).
- the file netdb.h is used to define the function gethostbyname (to
convert a host name to an IP address). In reviewing some other on line
resources, it appears this may be defined by including winsock.h
instead. Try replacing lines
#include <netdb.h> (and any others that are "missing")
with the single line
#include <winsock.h>
and tell me the *exact* error messages [or if it builds OK and runs].
By providing this information (and a possible follow on), I can
provide code that will build correctly on both your and my system with
a preprocessor directive.
On the #1 alternative, I don't know how that will help you. It is
likely I would generate an executable that would still run on a system
I have access to you and won't run on yours. You would also not be
able to make any changes to fix a last minute problem.
If you still want help & need this by next Wednesday (May 7) - I
suggest checking / providing feedback more frequently (at least
daily).
--Maniac
|
Clarification of Question by
questionboy-ga
on
30 Apr 2003 22:54 PDT
Hello, Manaic:
The followings are the 3 different methods I did:
1) I tried to run the original program you gave me before, and there
are two errors (the following is the EXACT error message from dgen,
dcache).
Cannot open include file:'netdb.h': no such file or directory
2) I tried to run the "replacement" (I used #include <winsock.h>
instead of #include <netdb.h>), and there are two errors.
Cannot open include file:'unistd.h': no such file or directory
3) Even though I knew "unistd.h" is needed, I still tried to delete
it from the error messages and compile it again. However, there are
still errors messages.
Cannot open include file:'sys/socket.h': no such file or directory
If I keep deleting certain files, there will be more error messages
arised.
|
Request for Question Clarification by
maniac-ga
on
01 May 2003 05:06 PDT
Hello Questionboy,
From what you said I have determined a few differences between the way
sockets are implemented in Visual C++ compared with the compilers I am
using. For example,
- <unistd.h> is used to define the close() and sleep() functions.
- <sys/socket.h> is used to define constants used for socket
operations.
Since these are not available on your system, we must use something
else.
I did a search using Visual C++ "close socket" and found several pages
with example code and one with a pretty good explanation of several
differences at
http://docs.rinet.ru:8083/VidimyyC/vcu39fi.htm
which indicates the version for your machine must...
- add a declaration near the top (after the #include directives)
static WSADATA wsaData;
to hold some WinSock specific information.
- add a WinSock initialization call with something like...
if (status(WSAStartup(0x0101, &wsaData), "ERROR", "WinSock Startup",
"main"))
exit(EXIT_FAILURE);
to initialize the WinSock DLL (and if it fails, dump an error message
and exit). The first parameter indicates the version you want, this
may need to change if we have problems later.
- replace the close() calls with closesocket(); apparently WinSock
requires this special call. For example,
close(my_socket);
should now be
closesocket(my_socket);
- add a call to WSACleanup() to the cleanup function to stop use of
WinSock. From the documentation there are some cases where this can
fail, but we can handle that later.
Let me know if this explanation is clear or if I need to send a test
program to check this out.
The use of sleep() is simply to wait a period (e.g., if the connection
doesn't succeed immediately). I am not sure with your system, but it
may be possible to add
#include <windows.h>
and use Sleep() instead of sleep(). If this works, let me know.
If there are more header files you are having problems with - continue
to remove them and report any further errors.
--Maniac
|
Clarification of Question by
questionboy-ga
on
01 May 2003 14:11 PDT
Hello, Manaic:
could you send me a test program to check this out.
Thank you very much
|
Request for Question Clarification by
maniac-ga
on
01 May 2003 18:01 PDT
Hello Questionboy,
This is a slimmed down test program that should verify:
- the macro definition is OK (_WIN32)
- the header files are set up OK
- we can examine the command line arguments
- the WinSock library is initialized OK
- the sleep works OK
Let me know if there are any problems building or running the
application. Please provide exact error messages if you can.
Build the application. Run as a command line program w/o any
parameters. Run again with localhost as the first parameter. You
should get something like the following as ouput:
dtest: arguments 2
./dtest: arg1 is localhost
dtest: socket succeeded
dtest: sleep done
There are some slight differences in the output you get - please
respond with the exact messages so I can confirm the right code is
working in each place.
--Maniac
dtest.c follows:
/*
* dtest.c
*/
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#if defined(_WIN32)
#include <windows.h>
#include <winsock.h>
static WSADATA WSAdata;
static SOCKET my_socket = INVALID_SOCKET;
#elif defined(__GNUC__)
/* above should probably be a posix declaration */
#include <sys/socket.h>
#include <unistd.h>
static int my_socket = 0;
#endif
int main(int argc,
char *argv[])
{
int retval;
fprintf(stdout, "dtest: arguments %d\n", argc);
if (argc >= 2)
fprintf(stdout, "%s: arg1 is %s\n", argv[0], argv[1]);
#ifdef _WIN32
/* initialize the WinSock DLL (version 1.1) */
retval = WSAStartup (0x0101, &WSAData);
if (retval != 0)
{
fprintf(stderr, "dtest: WSAStartup failed\n");
perror("dtest");
exit(EXIT_FAILURE);
}
#endif
my_socket = socket(PF_INET, SOCK_STREAM, 0);
if (my_socket < 0)
{
fprintf(stderr, "dtest: socket failed\n");
perror("dtest");
exit(EXIT_FAILURE);
}
fprintf(stdout, "dtest: socket succeeded\n");
#ifdef _WIN32
Sleep(1000);
fprintf(stdout, "dtest: Sleep done\n");
closesocket(my_socket);
WSACleanup();
#else
sleep(1); /* sleep a second */
fprintf(stdout, "dtest: sleep done\n");
close(my_socket);
#endif
}
|
Clarification of Question by
questionboy-ga
on
01 May 2003 23:22 PDT
Hello, Manaic:
I tested it. The followings are the messages:
test.obj - 1 error(s), 1 warning(s)
d:\program files\microsoft visual studio\myprojects\test\test.cpp(31)
: error
C2275: 'WSAData' : illegal use of this type as an expressiond:\program
d:\program files\microsoft visual studio\vc98\include\winsock.h(319) :
see declaration of 'WSAData'
d:\program files\microsoft visual studio\myprojects\test\test.cpp(60)
: warning C4508: 'main' : function should return a value; 'void'
return type assumed
Error executing cl.exe.
After testing, I went to check winsock.h(319), the following is about
declaration of 'WSAData'
/*
* Socket address, internet style.
*/
struct sockaddr_in {
short sin_family;
u_short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
#define WSADESCRIPTION_LEN 256
#define WSASYS_STATUS_LEN 128
typedef struct WSAData {
WORD wVersion;
WORD wHighVersion;
char szDescription[WSADESCRIPTION_LEN+1];
char szSystemStatus[WSASYS_STATUS_LEN+1];
unsigned short iMaxSockets;
unsigned short iMaxUdpDg;
char FAR * lpVendorInfo;
} WSADATA;
typedef WSADATA FAR *LPWSADATA;
|
Request for Question Clarification by
maniac-ga
on
02 May 2003 04:22 PDT
Hello Questionboy,
OK. Line 31 is the WSAStartup call. There is a typo - WSAData is not
the same as WSAdata (defined on line 11). Change line 11 to read
static WSADATA WSAData;
to fix this.
OK. Line 60 is the end of the main function. Since main is supposed to
return an int, it should have a return statement. Make the following
changes:
Line 23 -
int retval = EXIT_SUCCESS;
Line 60 -
return retval;
to fix this problem.
That should fix the compile problems you indicated. Let me know what
happens next and we can proceed to the next step.
--Maniac
|
Clarification of Question by
questionboy-ga
on
02 May 2003 11:12 PDT
Hello, Manaic:
I compiled it, and then the message was:
*************************************************
Compiling...
Skipping... (no relevant changes detected)
est.cpp
est.obj - 0 error(s), 0 warning(s)
*************************************************
However, when I built it, the message was:
*************************************************
Linking...
est.obj : error LNK2001: unresolved external symbol _WSACleanup@0
est.obj : error LNK2001: unresolved external symbol _closesocket@4
est.obj : error LNK2001: unresolved external symbol _socket@12
est.obj : error LNK2001: unresolved external symbol _WSAStartup@8
LIBCD.lib(wincrt0.obj) : error LNK2001: unresolved external symbol _WinMain@16
Debug/test.exe : fatal error LNK1120: 5 unresolved externals
Error executing link.exe.
test.exe - 6 error(s), 0 warning(s)
*****************************************************************
the following was fixed that you told me
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#if defined(_WIN32)
#include <windows.h>
#include <winsock.h>
static WSADATA WSAData;
static SOCKET my_socket = INVALID_SOCKET;
#elif defined(__GNUC__)
/* above should probably be a posix declaration */
#include <sys/socket.h>
#include <unistd.h>
static int my_socket = 0;
#endif
int main(int argc,
char *argv[])
{
int retval = EXIT_SUCCESS;
fprintf(stdout, "dtest: arguments %d\n", argc);
if (argc >= 2)
fprintf(stdout, "%s: arg1 is %s\n", argv[0], argv[1]);
#ifdef _WIN32
/* initialize the WinSock DLL (version 1.1) */
retval = WSAStartup (0x0101, &WSAData);
if (retval != 0)
{
fprintf(stderr, "dtest: WSAStartup failed\n");
perror("dtest");
exit(EXIT_FAILURE);
}
#endif
my_socket = socket(PF_INET, SOCK_STREAM, 0);
if (my_socket < 0)
{
fprintf(stderr, "dtest: socket failed\n");
perror("dtest");
exit(EXIT_FAILURE);
}
fprintf(stdout, "dtest: socket succeeded\n");
#ifdef _WIN32
Sleep(1000);
fprintf(stdout, "dtest: Sleep done\n");
closesocket(my_socket);
WSACleanup();
#else
sleep(1); /* sleep a second */
fprintf(stdout, "dtest: sleep done\n");
close(my_socket);
#endif
return retval;
}
|
Request for Question Clarification by
maniac-ga
on
03 May 2003 06:38 PDT
Hello Questionboy,
You need to add wsock32.lib (or perhaps ws2_32.lib) to the build
process. See
http://williams.cs.ncat.edu/Networks/wsock32.htm
or
http://www.sockets.com/a_d.htm
for an explanation. I found references to both of these libraries;
perhaps one is a later version than the other. If the first doesn't
work, try the other.
[add the object / library module to the project settings, link tab]
Your source code looks OK (though you may want to add the return
statement at the end as suggested before to get rid of a warning).
--Maniac
|
Clarification of Question by
questionboy-ga
on
03 May 2003 09:39 PDT
Hello, Manaic:
I added wsock32.lib, and then compiled and built it.
It worked. The Execute program showed below:
dtest: arguments 1
dtest: socket succeeded
dtest: Sleep done
Press any key to continue
Thanks a lot
|
Request for Question Clarification by
maniac-ga
on
03 May 2003 20:00 PDT
Hello Questionboy,
Good. I have some work to do with the current version of the main
programs (cache & data generator) to incorporate the same changes made
to the test program. Separately, the data generator is almost done
(once the updates are done). The cache program needs to receive and
process the data plus respond to other data requesters.
If the work goes well (and it works on your system), I will try to
wrap this up tomorrow (Sunday) so you have more time to test the
program on the systems you have access.
--Maniac
|
Request for Question Clarification by
maniac-ga
on
04 May 2003 11:44 PDT
Hello Questionboy,
When you execute the test program, can you specify a command line
argument?
I want to make sure you can specify the host of the data generation
program (or data caching program) when you start up each caching
application (instead of using some other method). From what I found
about Visual C++, you must generate the .exe file and run it from a
console window. If you can do this, please let me know what the output
is and if you can't, tell me what you tried so I can suggest some
alternatives.
--Maniac
|
Clarification of Question by
questionboy-ga
on
04 May 2003 13:34 PDT
Hello, Manaic:
I don't understand what do you mean.
After I compiled the test program, it showed below:
--------------------Configuration: test - Win32 Debug--------
Compiling...
Skipping... (no relevant changes detected)
test.cpp
test.obj - 0 error(s), 0 warning(s)
After I built it, it showed below:
--------------------Configuration: test - Win32 Debug--------
Linking...
test.exe - 0 error(s), 0 warning(s)
when I executed the program, the console window showed below:
--------------------------------------------------------------
dtest: arguments 1
dtest: socket succeeded
dtest: Sleep done
Press any key to continue
|
Request for Question Clarification by
maniac-ga
on
04 May 2003 20:17 PDT
Hello Questionboy,
About the command line arguments - from your explanation, it appears
you are still running the program from Visual C++. With Windows 2000,
you can bring up one with the start menu (which will allow you to run
the program more than once). Alternatively from the start menu, use
Run...
and enter the location of the program (including .exe), a space, and
the a command line argument such as localhost. Something like...
D:\google\dnet\dtest.exe localhost
should do the job [replace the first parameter w/ the location of your
.exe file].
I'd still like the results of that test (where the program says
arguments 2 or greater) because you will need that to run the cache
application [to tell it where to connect to].
In the meantime, the data generator appears to be pretty complete. I
don't think it needs further work unless it won't build on your
system. The cache application is almost done. I'm sending the current
version since we need to confirm that both applications will build and
work on your system (so we can fix it). The following assumes it
builds OK. If not, I'll need full error messages again and we can
repeat like with dtest.
The data generator will now allow multiple systems to connect. Each
system will get a message at about once per second with the current
date/time and a sequence number. A line will be printed when all
messages are sent so you can compare with other systems.
The data cache application will now connect with the data generator.
You do have to specify the host to connect to. The command line
parameter "localhost" (without quotes) refers to the PC it is running
on. I was able to run two copies of the data cache application with
the data generator without problem. Each printed the date/time in sync
with the data generator.
On my system, the output looks something like this:
./dgen
./dgen: Seq #0, time is Sun May 4 21:39:51 2003
./dgen: Seq #1, time is Sun May 4 21:39:52 2003
./dgen: Seq #2, time is Sun May 4 21:39:53 2003
[repeats every second]
(on another console window...)
./dcache localhost
./dcache: Seq #0, time is Sun May 4 21:39:51 2003
./dcache: Seq #1, time is Sun May 4 21:39:52 2003
./dcache: Seq #2, time is Sun May 4 21:39:53 2003
[repeats every second]
(on a third console window...)
./dcache localhost
./dcache: Seq #5, time is Sun May 4 21:39:56 2003
./dcache: Seq #6, time is Sun May 4 21:39:57 2003
./dcache: Seq #7, time is Sun May 4 21:39:58 2003
[repeats every second - note this last sequence starts w/ 5 - I
started it about 5 seconds after the first cache application. The
date/time format may be different on your system; that would be OK.
This also illustrates the one missing function of the cache (sending
saved values). This last function would be tested best on two or more
systems (not just with "localhost") since each cache application will
try to respond to the same port numbers.
Running on your system should be similar to what I described above if
you are using console windows. Replace the first part (e.g., ./dgen)
with the location of your .exe file in each example. Run the data
generator first, then the cache applications [though the cache
application will wait if needed].
The updated source code follows.
--Maniac
--- dapp.h ---
/*
* dapp.h -- header file for distributed generator / cache application
*/
#ifndef __DAPP
/* TCP port number to use */
#define DPORT 2525
#define SLOTS 10
/*
* data_buffer
* sequence - sequence number for validity check
* slot - a slot number, increases each pass modulo SLOTS
* now - the time in seconds
*/
struct data_buffer {
int sequence;
int slot;
time_t now;
};
/*
* data_cache
* sequence - last sequence number
* times - the times collected
* to generalize the cache, replace the array with a structure type
*/
struct data_cache {
int sequence;
time_t times[SLOTS];
};
#define __DAPP
#endif
--- dgen.c ---
/*
* dgen.c -- distributed data generator
*/
/* system includes */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <sys/types.h>
/*
* conditional compile for Unix / Windows differences
*/
#if defined(_WIN32)
#include <windows.h>
#include <winsock.h>
static WSADATA WSAData;
static SOCKET conn_socket = INVALID_SOCKET;
#define CLSOCK closesocket
#define DELAY Sleep(1000)
#elif defined(__GNUC__)
/* above should probably be a posix declaration */
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <unistd.h>
#include <fcntl.h>
static int conn_socket = 0; /* connection socket number */
#define CLSOCK close
#define MYDELAY sleep(1)
#else
#error "Not set up for this system type, please fix the code"
#endif
#include "dapp.h"
static char *pname; /* name of this application */
static int my_port = DPORT; /* tcp port connection */
static int flag_conn = 0; /* have connection socket */
static struct data_cache the_source; /* the master copy of data */
/* note - sequence used on data generator to count cycles / set slots
*/
struct rbuff;
struct rbuff {
struct rbuff *next;
int cache_socket;
int seq;
};
static struct rbuff *caches;
/*************************************************************
* helper to dump error messages
* pass retval back for use in if statement
*************************************************************/
int status(int retval,
char *level,
char *what,
char *where)
{
if (retval)
{
fprintf(stderr, "%s: %s - %s failed in %s\n",
pname, level, what, where);
perror(pname);
}
return retval;
}
/*************************************************************
* helper to handle nasty non-blocking I/O set up
*************************************************************/
void nonblock(int fd)
{
#if defined(WIN32)
u_long flag = 1;
if (status((ioctlsocket(fd, FIONBIO, &flag) == -1),
"ERROR", "non-blocking I/O", "nonblock"))
exit(EXIT_FAILURE);
#else
int flags = fcntl(fd, F_GETFL, 0);
flags |= O_NONBLOCK|O_NDELAY;
if (status((fcntl(fd, F_SETFL, flags) == -1),
"ERROR", "non-blocking I/O", "nonblock"))
exit(EXIT_FAILURE);
#endif
}
/*************************************************************
* clean up the application
*************************************************************/
void cleanup()
{
if (flag_conn)
(void)CLSOCK(conn_socket); /* ignore errors */
#if defined(_WIN32)
WSACleanup();
#endif
}
/*************************************************************
* establish the socket connection
* return value is the socket to the first reader
*************************************************************/
int init_socket()
{
struct sockaddr_in my_sockdata;
int my_sockdata_len = sizeof(my_sockdata);
int retval;
int cache_socket = 0;
conn_socket = socket(PF_INET, SOCK_STREAM, 0);
if (status((conn_socket < 0), "ERROR", "socket", "init_socket"))
exit(EXIT_FAILURE);
flag_conn++;
bzero ((char *)&my_sockdata, sizeof(my_sockdata));
my_sockdata.sin_family = AF_INET;
my_sockdata.sin_port = htons(my_port);
my_sockdata.sin_addr.s_addr = htonl(INADDR_ANY);
retval = bind (conn_socket, (struct sockaddr*) &my_sockdata,
sizeof(my_sockdata));
if (status(retval, "ERROR", "bind", "init_socket"))
exit(EXIT_FAILURE);
retval = listen (conn_socket, 1); /* listen for one at a time */
if (status(retval, "ERROR", "listen", "init_socket"))
exit(EXIT_FAILURE);
/* this will block - don't bother with data generation until
* we have a cache reading application */
cache_socket = accept (conn_socket, (struct sockaddr*) &my_sockdata,
&my_sockdata_len);
retval = (cache_socket < 0);
if (status(retval, "ERROR", "accept", "init_socket"))
exit(EXIT_FAILURE);
/* at this point, mark the accept socket as non blocking */
nonblock(conn_socket);
return cache_socket;
}
/*************************************************************
* initialize the socket to the cache system
*************************************************************/
void init_cache(int cache_socket)
{
struct rbuff *buf;
buf = calloc(1, sizeof(struct rbuff));
if (status((buf==NULL), "ERROR", "calloc", "init_cache"))
exit(EXIT_FAILURE);
/* insert this buffer into the cache list */
buf->next = caches;
buf->seq = 0;
buf->cache_socket = cache_socket;
caches = buf;
}
/*************************************************************
* initialize the application
* register the exit procedure
* handle command line arguments
* get the socket
*************************************************************/
void initialize(int argc,
char *argv[])
{
int cache_socket;
if (status(atexit(cleanup), "ERROR", "atexit", "initialize"))
exit(EXIT_FAILURE);
/* capture program name */
pname = argv[0];
#if defined(_WIN32)
/* initialize the WinSock DLL (version 1.1) */
retval = WSAStartup (0x0101, &WSAData);
if (retval != 0)
{
fprintf(stderr, "dtest: WSAStartup failed\n");
perror("dtest");
exit(EXIT_FAILURE);
}
#endif
cache_socket = init_socket();
init_cache(cache_socket);
the_source.sequence = 0; /* never sent any data */
}
/*************************************************************
* accept additional connections
*************************************************************/
void accept_socket() {
struct sockaddr_in my_sockdata;
int my_sockdata_len = sizeof(my_sockdata);
int cache_socket = 0;
/* this will not block - continue on any error */
cache_socket = accept (conn_socket, (struct sockaddr*) &my_sockdata,
&my_sockdata_len);
if (cache_socket > 0)
init_cache(cache_socket);
}
int main (int argc,
char * argv[])
{
struct rbuff *next;
struct rbuff *last;
struct rbuff *temp;
struct data_buffer buff;
time_t its_now;
ssize_t bytes;
initialize(argc, argv);
/* keep sending data - until all readers are gone */
while (caches != NULL) {
next = caches;
last = NULL;
its_now = time(NULL);
the_source.times[the_source.sequence % SLOTS] = its_now;
while (next != NULL) {
buff.sequence = the_source.sequence;
buff.slot = the_source.sequence % SLOTS;
buff.now = its_now;
/* note - not blocking send */
bytes = send(next->cache_socket, &buff,
sizeof(struct data_buffer), MSG_DONTWAIT);
if (bytes <= 0)
{ /* we have lost connection with the destination */
/* remove this item from the linked list */
if (last == NULL)
{
/* fprintf(stdout, "head - caches:%p, next:%p,
next->next:%p\n", */
/* caches, next, next->next); */
caches = next->next;
}
else
{
/* fprintf(stdout, "mid - last:%p, next:%p, next->next:%p\n",
*/
/* last, next, next->next); */
last->next = next->next;
}
/* close the socket, release memory & bump to next list item */
(void)CLSOCK(next->cache_socket);
temp = next;
next = next->next;
(void)free(temp);
}
else
{
last = next;
next = next->next;
}
}
/* have sent all the messages to the other systems */
/* print a message, check the connect socket & delay a moment */
/* note that ctime returns string w/ new line */
fprintf(stdout, "%s: Seq #%d, time is %s",
pname, the_source.sequence, ctime(&its_now));
the_source.sequence++;
accept_socket();
MYDELAY;
}
return EXIT_SUCCESS;
}
--- dcache.c ---
/*
* dcache.c -- distributed cache application
*/
/* system includes */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <sys/types.h>
/*
* conditional compile for Unix / Windows differences
*/
#if defined(_WIN32)
#include <windows.h>
#include <winsock.h>
static WSADATA WSAData;
static SOCKET my_socket = INVALID_SOCKET;
static u_long remote_addr = 0; /* address of remote host */
#define CLSOCK closesocket
#elif defined(__GNUC__)
/* above should probably be a posix declaration */
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <unistd.h>
static int my_socket = 0; /* connection socket number */
static u_int32_t remote_addr = 0; /* address of remote host */
#define CLSOCK close
#else
#error "Not set up for this system type, please fix the code"
#endif
#include "dapp.h"
static char *pname; /* name of this application */
static int flag_tcp = 0; /* link connected if non zero */
static int my_port = DPORT; /* tcp port connection */
static struct data_cache my_cache;
/*************************************************************
* helper to dump error messages
* pass retval back for use in if statement
*************************************************************/
int status(int retval,
char *level,
char *what,
char *where)
{
if (retval)
{
fprintf(stderr, "%s: %s - %s failed in %s\n",
pname, level, what, where);
perror(pname);
}
return retval;
}
/*************************************************************
* clean up the application
*************************************************************/
void cleanup()
{
#if defined(_WIN32)
WSACleanup();
#endif
}
/*************************************************************
* establish the socket connection
*************************************************************/
void init_socket()
{
int retval;
struct sockaddr_in my_sockdata;
const int conn_delay = 10;
while (1)
{
my_socket = socket(PF_INET, SOCK_STREAM, 0);
retval = (my_socket < 0);
if (status(retval, "ERROR", "socket", "init_socket"))
exit(EXIT_FAILURE);
/* establish the connection */
bzero ((char *)&my_sockdata, sizeof(my_sockdata));
my_sockdata.sin_family = AF_INET;
my_sockdata.sin_port = htons(my_port);
my_sockdata.sin_addr.s_addr = remote_addr;
retval = connect(my_socket, (struct sockaddr*) &my_sockdata,
sizeof(my_sockdata));
if (retval == 0)
break; /* success */
else if (errno == ECONNREFUSED)
{
close(my_socket); /* socket unusable - close it */
fprintf(stderr, "%s: STATUS - ECONNREFUSED, retry in %d
seconds.\n",
pname, conn_delay);
sleep(conn_delay);
}
else
{
status (retval, "ERROR", "connect", "init_socket");
exit(EXIT_FAILURE);
}
}
flag_tcp++; /* note connection established */
}
/*************************************************************
* initialize the application
* register the exit procedure
* handle command line arguments
* get the socket
*************************************************************/
void initialize(int argc,
char *argv[])
{
int retval;
struct hostent *remote_host;
if (status(atexit(cleanup), "ERROR", "atexit", "initialize"))
exit(EXIT_FAILURE);
/* capture program name */
pname = argv[0];
#if defined(_WIN32)
/* initialize the WinSock DLL (version 1.1) */
retval = WSAStartup (0x0101, &WSAData);
if (retval != 0)
{
fprintf(stderr, "dtest: WSAStartup failed\n");
perror("dtest");
exit(EXIT_FAILURE);
}
#endif
/* get address of remote host */
if (status((argc <= 1), "ERROR", "argc > 1", "initialize"))
exit(EXIT_FAILURE);
remote_host = gethostbyname(argv[1]);
retval = (remote_host == (void *) 0);
if (status(retval, "ERROR", "gethostbyname", "initialize"))
exit(EXIT_FAILURE);
retval = (remote_host->h_length > sizeof(remote_addr));
if (status(retval, "ERROR", "remote address fits", "initialize"))
exit(EXIT_FAILURE);
retval = (remote_host->h_addr_list[0] == (void *)0);
if (status(retval, "ERROR", "remote address valid", "initialize"))
exit(EXIT_FAILURE);
memcpy(&remote_addr, remote_host->h_addr_list[0],
remote_host->h_length);
init_socket();
}
/*************************************************************
* main program
*************************************************************/
int main (int argc,
char * argv[])
{
struct data_buffer buff;
ssize_t bytes;
initialize(argc, argv);
while (1)
{
/* blocking read */
bytes = recv(my_socket, &buff,
sizeof(struct data_buffer), 0);
if (bytes <= 0)
break; /* lost connection, exit */
if (my_cache.sequence == 0)
my_cache.sequence = buff.sequence; /* first time alignment */
if (status((my_cache.sequence++ != buff.sequence),
"ERROR", "sequence mismatch", "main"))
exit(EXIT_FAILURE);
my_cache.times[buff.slot] = buff.now;
fprintf(stdout, "%s: Seq #%d, time is %s",
pname, buff.sequence, ctime(&buff.now));
}
return EXIT_SUCCESS;
}
|
Clarification of Question by
questionboy-ga
on
04 May 2003 21:25 PDT
Hello, Manaic:
below were command line arguments:
D:\test\Debug>test .exe
dtest: arguments 2
test: arg1 is .exe
dtest: socket succeeded
dtest: Sleep done
D:\test\Debug>test .exe localhost
dtest: arguments 3
test: arg1 is .exe
dtest: socket succeeded
dtest: Sleep done
|
Clarification of Question by
questionboy-ga
on
04 May 2003 22:33 PDT
Hello, Manaic:
I created 1 Header File and 2 Source Files, when I compiled, the
messages showed below:
--------------------Configuration: network - Win32
Debug--------------------
Compiling...
dcache.c
D:\network\dcache.c(94) : warning C4013: 'bzero' undefined; assuming
extern returning int
D:\network\dcache.c(102) : error C2065: 'ECONNREFUSED' : undeclared
identifier
D:\network\dcache.c(104) : warning C4013: 'close' undefined; assuming
extern returning int
D:\network\dcache.c(105) : error C2001: newline in constant
D:\network\dcache.c(106) : error C2146: syntax error : missing ')'
before identifier 'seconds'
D:\network\dcache.c(106) : error C2017: illegal escape sequence
D:\network\dcache.c(106) : error C2001: newline in constant
D:\network\dcache.c(107) : error C2059: syntax error : ')'
D:\network\dcache.c(108) : warning C4013: 'sleep' undefined; assuming
extern returning int
D:\network\dcache.c(133) : warning C4113: 'void (__cdecl *)()' differs
in parameter lists from 'void (__cdecl *)(void )'
D:\network\dcache.c(178) : error C2065: 'ssize_t' : undeclared
identifier
D:\network\dcache.c(178) : error C2146: syntax error : missing ';'
before identifier 'bytes'
D:\network\dcache.c(178) : error C2065: 'bytes' : undeclared
identifier
D:\network\dcache.c(184) : warning C4133: 'function' : incompatible
types - from 'struct data_buffer *' to 'char *'
dgen.c
D:\network\dgen.c(127) : warning C4013: 'bzero' undefined; assuming
extern returning int
D:\network\dgen.c(185) : warning C4113: 'void (__cdecl *)()' differs
in parameter lists from 'void (__cdecl *)(void )'
D:\network\dgen.c(193) : error C2065: 'retval' : undeclared identifier
D:\network\dgen.c(233) : error C2065: 'ssize_t' : undeclared
identifier
D:\network\dgen.c(233) : error C2146: syntax error : missing ';'
before identifier 'bytes'
D:\network\dgen.c(233) : error C2065: 'bytes' : undeclared identifier
D:\network\dgen.c(247) : warning C4133: 'function' : incompatible
types - from 'struct data_buffer *' to 'const char *'
D:\network\dgen.c(248) : error C2065: 'MSG_DONTWAIT' : undeclared
identifier
D:\network\dgen.c(285) : error C2065: 'MYDELAY' : undeclared
identifier
Error executing cl.exe.
network.exe - 15 error(s), 8 warning(s)
**************************************************************************
However, when I only created 1 Source File including dapp.h dgen.c
dcache.c
the message showed below:
--------------------Configuration: none - Win32
Debug--------------------
Compiling...
none.cpp
D:\none\none.cpp(22) : error C2146: syntax error : missing ';' before
identifier 'now'
D:\none\none.cpp(22) : error C2501: 'time_t' : missing storage-class
or type specifiers
D:\none\none.cpp(22) : error C2501: 'now' : missing storage-class or
type specifiers
D:\none\none.cpp(34) : error C2146: syntax error : missing ';' before
identifier 'times'
D:\none\none.cpp(34) : error C2501: 'time_t' : missing storage-class
or type specifiers
D:\none\none.cpp(34) : error C2501: 'times' : missing storage-class or
type specifiers
D:\none\none.cpp(80) : fatal error C1083: Cannot open include file:
'dapp.h': No such file or directory
Error executing cl.exe.
none.exe - 7 error(s), 0 warning(s)
|
Request for Question Clarification by
maniac-ga
on
05 May 2003 05:34 PDT
Hello Questionboy,
On the command line examples, they should read
test.exe localhost
or
test localhost
It appears that windows found the executable w/o the .exe on your
system.
On the code problems, let's work with the three files (not the single
one) since you will need two main programs (not one).
dcache.c -
Grr. Replace line 94 with
memset (&my_sockdata, 0, sizeof(my_sockdata));
Apparently bzero was not implemented by Microsoft.
The use of ECONNREFUSED (line 102) points out another compatibility
problem. Windows has a separate error reporting method for sockets
from other errors - I am not sure why. Let's apply a simple fix for
now and assume that any error is equal to ECONNREFUSED here. Revise
that section to read:
if (retval == 0)
break; /* success */
else
{
CLSOCK(my_socket); /* socket unusable - close it */
fprintf(stderr,
"%s: STATUS - ECONNREFUSED, retry in 10 seconds.\n",
pname);
MYDELAY;
}
[this includes the next few fixes...]
Replace line 104 with
CLSOCK(my_socket); /* socket unusable - close it */
At lines 105 ... the string constant was broken into two lines, make
it one. Perhaps something like
fprintf(stderr,
"%s: STATUS - ECONNREFUSED, retry in 10 seconds.\n",
pname);
[should appear as three lines, not four or more]
To fix line 108, change it from
sleep(conn_delay);
to read
MYDELAY;
and add a line at 23 (inside #if defined (_WIN32))
#define MYDELAY Sleep(10000)
and at line 36 (inside #elsif defined (__GNUC__))
#define MYDELAY sleep(10)
[I fixed the delay in one program and forgot this one]
The warning on 133 is pretty odd. Visual C++ apparently is complaining
that the cleanup function was declared as
void cleanup( )
and not
void cleanup( void )
even though that should be equivalent. Make the fix at about line 71.
At line 178, change ssize_t to int.
At line 184, change it to read
bytes = recv(my_socket, (char *)&buff,
sizeof(struct data_buffer), 0);
[add a type cast to char *]
dgen.c
Same fix for bzero
memset (&my_sockdata, 0, sizeof(my_sockdata));
Same fix for cleanup
void cleanup( void )
For line 193, add near 183 (after int cache_socket)
#if defined (_WIN32)
int retval;
#endif
to declare retval.
Line 233, replace ssize_t with int
Line 247, add (char *) before &buff
[same fix as above for recv line]
On line 248, another "not implemented" problem. I already added the
"nonblock" function to this file, so add
nonblock(cache_socket);
at line 170 (the end of init_cache function and change MSG_DONTWAIT to
0 on line 248.
On line 285, this does not make sense - MYDELAY is declared at line
22, perhaps one of the other errors is causing this. Let me know if it
recurs.
--Maniac
|
Clarification of Question by
questionboy-ga
on
05 May 2003 16:47 PDT
Hello, Manaic:
the followings are fixed:
/*
* dgen.c -- distributed data generator
*/
/* system includes */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <sys/types.h>
/*
* conditional compile for Unix / Windows differences
*/
#if defined(_WIN32)
#include <windows.h>
#include <winsock.h>
static WSADATA WSAData;
static SOCKET conn_socket = INVALID_SOCKET;
#define CLSOCK closesocket
#define DELAY Sleep(1000)
#elif defined(__GNUC__)
/* above should probably be a posix declaration */
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <unistd.h>
#include <fcntl.h>
static int conn_socket = 0; /* connection socket number */
#define CLSOCK close
#define MYDELAY sleep(1)
#else
#error "Not set up for this system type, please fix the code"
#endif
#include "dapp.h"
static char *pname; /* name of this application */
static int my_port = DPORT; /* tcp port connection */
static int flag_conn = 0; /* have connection socket */
static struct data_cache the_source; /* the master copy of data */
/* note - sequence used on data generator to count cycles / set slots
*/
struct rbuff;
struct rbuff {
struct rbuff *next;
int cache_socket;
int seq;
};
static struct rbuff *caches;
/*************************************************************
* helper to dump error messages
* pass retval back for use in if statement
*************************************************************/
int status(int retval,
char *level,
char *what,
char *where)
{
if (retval)
{
fprintf(stderr, "%s: %s - %s failed in %s\n",
pname, level, what, where);
perror(pname);
}
return retval;
}
/*************************************************************
* helper to handle nasty non-blocking I/O set up
*************************************************************/
void nonblock(int fd)
{
#if defined(WIN32)
u_long flag = 1;
if (status((ioctlsocket(fd, FIONBIO, &flag) == -1),
"ERROR", "non-blocking I/O", "nonblock"))
exit(EXIT_FAILURE);
#else
int flags = fcntl(fd, F_GETFL, 0);
flags |= O_NONBLOCK|O_NDELAY;
if (status((fcntl(fd, F_SETFL, flags) == -1),
"ERROR", "non-blocking I/O", "nonblock"))
exit(EXIT_FAILURE);
#endif
}
/*************************************************************
* clean up the application
*************************************************************/
void cleanup(void)
{
if (flag_conn)
(void)CLSOCK(conn_socket); /* ignore errors */
#if defined(_WIN32)
WSACleanup();
#endif
}
/*************************************************************
* establish the socket connection
* return value is the socket to the first reader
*************************************************************/
int init_socket()
{
struct sockaddr_in my_sockdata;
int my_sockdata_len = sizeof(my_sockdata);
int retval;
int cache_socket = 0;
conn_socket = socket(PF_INET, SOCK_STREAM, 0);
if (status((conn_socket < 0), "ERROR", "socket", "init_socket"))
exit(EXIT_FAILURE);
flag_conn++;
memset (&my_sockdata, 0, sizeof(my_sockdata));
my_sockdata.sin_family = AF_INET;
my_sockdata.sin_port = htons(my_port);
my_sockdata.sin_addr.s_addr = htonl(INADDR_ANY);
retval = bind (conn_socket, (struct sockaddr*) &my_sockdata,
sizeof(my_sockdata));
if (status(retval, "ERROR", "bind", "init_socket"))
exit(EXIT_FAILURE);
retval = listen (conn_socket, 1); /* listen for one at a time */
if (status(retval, "ERROR", "listen", "init_socket"))
exit(EXIT_FAILURE);
/* this will block - don't bother with data generation until
* we have a cache reading application */
cache_socket = accept (conn_socket, (struct sockaddr*) &my_sockdata,
&my_sockdata_len);
retval = (cache_socket < 0);
if (status(retval, "ERROR", "accept", "init_socket"))
exit(EXIT_FAILURE);
/* at this point, mark the accept socket as non blocking */
nonblock(conn_socket);
return cache_socket;
}
/*************************************************************
* initialize the socket to the cache system
*************************************************************/
void init_cache(int cache_socket)
{
struct rbuff *buf;
buf = calloc(1, sizeof(struct rbuff));
if (status((buf==NULL), "ERROR", "calloc", "init_cache"))
exit(EXIT_FAILURE);
/* insert this buffer into the cache list */
buf->next = caches;
buf->seq = 0;
buf->cache_socket = cache_socket;
caches = buf;
nonblock(cache_socket);
}
/*************************************************************
* initialize the application
* register the exit procedure
* handle command line arguments
* get the socket
*************************************************************/
void initialize(int argc,
char *argv[])
{
int cache_socket;
#if defined(_WIN32)
int retval;
#endif
if (status(atexit(cleanup), "ERROR", "atexit", "initialize"))
exit(EXIT_FAILURE);
/* capture program name */
pname = argv[0];
#if defined(_WIN32)
/* initialize the WinSock DLL (version 1.1) */
retval = WSAStartup (0x0101, &WSAData);
if (retval != 0)
{
fprintf(stderr, "dtest: WSAStartup failed\n");
perror("dtest");
exit(EXIT_FAILURE);
}
#endif
cache_socket = init_socket();
init_cache(cache_socket);
the_source.sequence = 0; /* never sent any data */
}
/*************************************************************
* accept additional connections
*************************************************************/
void accept_socket() {
struct sockaddr_in my_sockdata;
int my_sockdata_len = sizeof(my_sockdata);
int cache_socket = 0;
/* this will not block - continue on any error */
cache_socket = accept (conn_socket, (struct sockaddr*) &my_sockdata,
&my_sockdata_len);
if (cache_socket > 0)
init_cache(cache_socket);
}
int main (int argc,
char * argv[])
{
struct rbuff *next;
struct rbuff *last;
struct rbuff *temp;
struct data_buffer buff;
time_t its_now;
int bytes;
initialize(argc, argv);
/* keep sending data - until all readers are gone */
while (caches != NULL) {
next = caches;
last = NULL;
its_now = time(NULL);
the_source.times[the_source.sequence % SLOTS] = its_now;
while (next != NULL) {
buff.sequence = the_source.sequence;
buff.slot = the_source.sequence % SLOTS;
buff.now = its_now;
/* note - not blocking send */
bytes = send(next->cache_socket, (char *) &buff,
sizeof(struct data_buffer), 0);
if (bytes <= 0)
{ /* we have lost connection with the destination */
/* remove this item from the linked list */
if (last == NULL)
{
/* fprintf(stdout, "head - caches:%p, next:%p,
next->next:%p\n", */
/* caches, next, next->next); */
caches = next->next;
}
else
{
/* fprintf(stdout, "mid - last:%p, next:%p, next->next:%p\n",
*/
/* last, next, next->next); */
last->next = next->next;
}
/* close the socket, release memory & bump to next list item */
(void)CLSOCK(next->cache_socket);
temp = next;
next = next->next;
(void)free(temp);
}
else
{
last = next;
next = next->next;
}
}
/* have sent all the messages to the other systems */
/* print a message, check the connect socket & delay a moment */
/* note that ctime returns string w/ new line */
fprintf(stdout, "%s: Seq #%d, time is %s",
pname, the_source.sequence, ctime(&its_now));
the_source.sequence++;
accept_socket();
MYDELAY;
}
return EXIT_SUCCESS;
}
/*
* dcache.c -- distributed cache application
*/
/* system includes */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <sys/types.h>
/*
* conditional compile for Unix / Windows differences
*/
#if defined(_WIN32)
#include <windows.h>
#include <winsock.h>
static WSADATA WSAData;
static SOCKET my_socket = INVALID_SOCKET;
static u_long remote_addr = 0; /* address of remote host */
#define CLSOCK closesocket
#define MYDELAY Sleep(10000)
#elif defined(__GNUC__)
/* above should probably be a posix declaration */
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <unistd.h>
static int my_socket = 0; /* connection socket number */
static u_int32_t remote_addr = 0; /* address of remote host */
#define CLSOCK close
#define MYDELAY sleep(10)
#else
#error "Not set up for this system type, please fix the code"
#endif
#include "dapp.h"
static char *pname; /* name of this application */
static int flag_tcp = 0; /* link connected if non zero */
static int my_port = DPORT; /* tcp port connection */
static struct data_cache my_cache;
/*************************************************************
* helper to dump error messages
* pass retval back for use in if statement
*************************************************************/
int status(int retval,
char *level,
char *what,
char *where)
{
if (retval)
{
fprintf(stderr, "%s: %s - %s failed in %s\n",
pname, level, what, where);
perror(pname);
}
return retval;
}
/*************************************************************
* clean up the application
*************************************************************/
void cleanup(void)
{
#if defined(_WIN32)
WSACleanup();
#endif
}
/*************************************************************
* establish the socket connection
*************************************************************/
void init_socket()
{
int retval;
struct sockaddr_in my_sockdata;
const int conn_delay = 10;
while (1)
{
my_socket = socket(PF_INET, SOCK_STREAM, 0);
retval = (my_socket < 0);
if (status(retval, "ERROR", "socket", "init_socket"))
exit(EXIT_FAILURE);
/* establish the connection */
memset (&my_sockdata, 0, sizeof(my_sockdata));
my_sockdata.sin_family = AF_INET;
my_sockdata.sin_port = htons(my_port);
my_sockdata.sin_addr.s_addr = remote_addr;
retval = connect(my_socket, (struct sockaddr*) &my_sockdata,
sizeof(my_sockdata));
if (retval == 0)
break; /* success */
else if (errno == ECONNREFUSED)
{
CLSOCK(my_socket); /* socket unusable - close it */
fprintf(stderr,
"%s: STATUS - ECONNREFUSED, retry in 10 seconds.\n",
pname);
MYDELAY;
}
else
{
status (retval, "ERROR", "connect", "init_socket");
exit(EXIT_FAILURE);
}
}
flag_tcp++; /* note connection established */
}
/*************************************************************
* initialize the application
* register the exit procedure
* handle command line arguments
* get the socket
*************************************************************/
void initialize(int argc,
char *argv[])
{
int retval;
struct hostent *remote_host;
if (status(atexit(cleanup), "ERROR", "atexit", "initialize"))
exit(EXIT_FAILURE);
/* capture program name */
pname = argv[0];
#if defined(_WIN32)
/* initialize the WinSock DLL (version 1.1) */
retval = WSAStartup (0x0101, &WSAData);
if (retval != 0)
{
fprintf(stderr, "dtest: WSAStartup failed\n");
perror("dtest");
exit(EXIT_FAILURE);
}
#endif
/* get address of remote host */
if (status((argc <= 1), "ERROR", "argc > 1", "initialize"))
exit(EXIT_FAILURE);
remote_host = gethostbyname(argv[1]);
retval = (remote_host == (void *) 0);
if (status(retval, "ERROR", "gethostbyname", "initialize"))
exit(EXIT_FAILURE);
retval = (remote_host->h_length > sizeof(remote_addr));
if (status(retval, "ERROR", "remote address fits", "initialize"))
exit(EXIT_FAILURE);
retval = (remote_host->h_addr_list[0] == (void *)0);
if (status(retval, "ERROR", "remote address valid", "initialize"))
exit(EXIT_FAILURE);
memcpy(&remote_addr, remote_host->h_addr_list[0],
remote_host->h_length);
init_socket();
}
/*************************************************************
* main program
*************************************************************/
int main (int argc,
char * argv[])
{
struct data_buffer buff;
int bytes;
initialize(argc, argv);
while (1)
{
/* blocking read */
bytes = recv(my_socket, (char *)&buff,
sizeof(struct data_buffer), 0);
if (bytes <= 0)
break; /* lost connection, exit */
if (my_cache.sequence == 0)
my_cache.sequence = buff.sequence; /* first time alignment */
if (status((my_cache.sequence++ != buff.sequence),
"ERROR", "sequence mismatch", "main"))
exit(EXIT_FAILURE);
my_cache.times[buff.slot] = buff.now;
fprintf(stdout, "%s: Seq #%d, time is %s",
pname, buff.sequence, ctime(&buff.now));
}
return EXIT_SUCCESS;
}
-------------------------------------
this was the result
--------------------Configuration: try - Win32 Debug-----------------
Compiling...
dgen.c
C:\Program Files\Microsoft Visual Studio\MyProjects\try\dgen.c(288) :
error C2065: 'MYDELAY' : undeclared identifier
dcache.c
C:\Program Files\Microsoft Visual Studio\MyProjects\try\dcache.c(104)
: error C2065: 'ECONNREFUSED' : undeclared identifier
Error executing cl.exe.
try.exe - 2 error(s), 0 warning(s)
|
Request for Question Clarification by
maniac-ga
on
05 May 2003 17:05 PDT
Hello Questionboy,
In dgen.c, line 22; change DELAY to MYDELAY. I'm not sure how the
incorrect definition crept into what I sent you. Hmm. I compared what
you sent me and the rest matches my copy.
In dcache.c, line 104; change
else if (errno == ECONNREFUSED)
to
else
and delete lines 112 through 116 (else and clause that follows it). I
can see what I described before was a little unclear.
I have another slight change in my file - you can remove line 86 since
we don't use conn_delay any more, but that should not affect the
operation of the program.
Those two changes should get rid of the compile errors. I'll be on for
the next few hours - try these two changes and get back with the
results.
Thanks.
--Maniac
|
Request for Question Clarification by
maniac-ga
on
05 May 2003 19:54 PDT
Hello Questionboy,
I have completed the updates to the data cache application. I was able
to run three copies of it, the second and third getting cached data
from the first data cache and all then getting data directly from the
data generator. I have to go to bed soon, so I won't be able to follow
up until tomorrow.
I will answer the question with the current version tomorrow, but will
prefer to fix any latent problems you have with the code already
provided. If you respond at your usual time (around 22:00 PDT)
tonight, I'll try to get on early (around 05:00 PDT) tomorrow with any
feedback, fixes to the code I have, and the full set of applications
w/ explanation of how the programs work.
--Maniac
|
Request for Question Clarification by
maniac-ga
on
06 May 2003 05:42 PDT
Hello Questionboy,
Please confirm that you can run the previously provided programs or
explain the difficulties you are having so I can fix the complete
version and send the files to you.
--Maniac
|
Clarification of Question by
questionboy-ga
on
06 May 2003 10:28 PDT
Hello, Manaic:
Sorry to let you wait. "In dgen.c, line 22; change DELAY to MYDELAY"
I am not really sure what your meaning is. In dgen.c, line 22 is
#define DELAY Sleep(1000), if I change it to
#define MYDELAY Sleep(1000), the message was:
--------------------Configuration: network - Win32 Debug--------
Compiling...
dgen.c
D:\network\dgen.c(129) : warning C4761: integral size mismatch in
argument; conversion supplied
Linking...
dgen.obj : error LNK2005: _status already defined in dcache.obj
dgen.obj : error LNK2005: _cleanup already defined in dcache.obj
dgen.obj : error LNK2005: _init_socket already defined in dcache.obj
dgen.obj : error LNK2005: _initialize already defined in dcache.obj
dgen.obj : error LNK2005: _main already defined in dcache.obj
Debug/network.exe : fatal error LNK1169: one or more multiply defined
symbols found
Error executing link.exe.
network.exe - 6 error(s), 1 warning(s)
**********************************************************
If I change it to #define MYDELAY, the message was:
--------------------Configuration: network - Win32
Debug--------------------
Linking...
dgen.obj : error LNK2005: _status already defined in dcache.obj
dgen.obj : error LNK2005: _cleanup already defined in dcache.obj
dgen.obj : error LNK2005: _init_socket already defined in dcache.obj
dgen.obj : error LNK2005: _initialize already defined in dcache.obj
dgen.obj : error LNK2005: _main already defined in dcache.obj
Debug/network.exe : fatal error LNK1169: one or more multiply defined
symbols found
Error executing link.exe.
network.exe - 6 error(s), 0 warning(s)
|
Request for Question Clarification by
maniac-ga
on
06 May 2003 13:04 PDT
Hello Questionboy,
As I mentioned before, you need to generate two main programs (one w/
dgen.c, the other w/ dcache.c). It appears you are linking both
together (with bad results).
To make it more clear...
dgen.exe is built from dgen.c and dapp.h
dcache.exe is built from dcache.c and dapp.h
(and both require the appropriate socket libraries, etc.)
It appears the compile is OK, let's work through the build and run
part now.
--Maniac
|
Clarification of Question by
questionboy-ga
on
06 May 2003 14:21 PDT
Hello, Manaic:
I compiled them separately. the results were below:
--------------------Configuration: dcache - Win32 Debug----
dcache.exe - 0 error(s), 0 warning(s)
-----------------------------------------------------------
After executed the program:
D:\dcache\Debug\dcache.exe: ERROR - argc > 1 failed in initialize
D:\dcache\Debug\dcache.exe: No error
Press any key to continue
--------------------Configuration: dgen - Win32 Debug---------
Compiling...
dgen.cpp
D:\dgen\dgen.cpp(162) : error C2440: '=' : cannot convert from 'void
*' to 'struct rbuff *'
Conversion from 'void*' to pointer to non-'void' requires an
explicit cast
Error executing cl.exe.
dgen.exe - 1 error(s), 0 warning(s)
|
Request for Question Clarification by
maniac-ga
on
06 May 2003 14:48 PDT
Hello Questionboy,
On running dcache.exe; remember that it must be run with a command
line parameter [like the dtest program was run]. For testing, run with
something like
dcache localhost
from a console window; suggest you run it after you get dgen fixed and
running.
On the problem with dgen.c; I assume this is the call to calloc. To
make the type cast, change it to read
buf = (rbuff *) calloc(1, sizeof(struct rbuff));
to convert the output of calloc (a pointer to any object) to a pointer
to an rbuff. I don't know why Visual C++ complained about it, but the
cast is easy to add. If it is somewhere else, let me know.
I also suggest you run dgen from a console window as well (though it
will run w/o any command line parameters) so you can see the output of
the program.
I suggest running
dgen
first (it won't print anything until dcache runs) and then run
dcache localhost
in a separate window (the same way you ran the test program). Once
both are running, you should see synchronized output with the date /
time values and sequence numbers increasing. Quitting either program
(e.g., hold Ctrl, and press C) will stop the other program as well.
Let me know how it works. I'll be off line a few hours but will check
back later tonight. If everything works OK, I'll fix / send the final
versions. If not, we can work past the next problem.
--Maniac
|
Clarification of Question by
questionboy-ga
on
06 May 2003 15:15 PDT
Hello, Manaic:
It works, I run dgen and then open another console window to run dcache.
The both windows print the same date / time values and sequence numbers increasing.
Thanks a lot
|
Clarification of Question by
questionboy-ga
on
06 May 2003 15:24 PDT
Hello, Manaic:
Can you also send me the document describing the objective, design and
implementation of this project. Any issues, lessons learned,
obstacles overcome should be noted.
thank you very much
|
Hello Questionboy,
Let's see if we can put this to rest. The material that follows
includes:
- a text file describing the objectives, design, notes & lessons
learned
- three source files (dgen.c, dcache.c, dapp.h) to produce the two
main programs (dgen, dcache)
- a Makefile that can be used on Unix systems to build the
application (I assume you already have suitable project file(s) for
Visual C++)
As I mentioned before, the data generator (dgen.c) should be the same
as what you already have. I am providing a new copy "just in case" I
forgot something.
If there are *any* problems with the material posted or further
questions, don't hesitate to use the clarification request so I can
follow up with more information. It has been an interesting problem to
look at and I hope you do well with your work.
--Maniac
----- dnet.txt -----
Distributed data generation and caching applications
====================================================
dgen.c - data generation application
dcache.c - data caching application
dapp.h - header file for both
Objectives
==========
The objectives are to demonstrate the ability to
- produce a distributed application
- cache information locally
- hand off between applications
- examine issues between Unix and Windows systems
The programs supplied meet these objectives.
Portability Notes
=================
Both applications are built to run on MS Windows using
Visual C++ or gcc and on Linux / Unix systems using gcc.
See conditional compilation using _WIN32 and __GNUC__
for the differences in implementation.
Programs / Messages
===================
The two main programs
- dgen, produced from dgen.c, dapp.h, and libraries
- dcache, produced from dcache.c, dapp.h, and libraries
uses TCP ports 2525 for the data generator and 2526 for the
caching applications. The cache in each instance of the
cache application has 10 slots of cached data. There are
two different message exchanged as follows:
data_buffer - a sequence number, slot number, and data.
For the test program, the data is simply the current date/time.
This can be generalized to any data type; see the notes at the
end for suggestions on how to do this.
dgen_buffer - a sequence number, and remote address.
Exchanged between cache applications to provide the current
sequence number and location of the data generator. This is
used to help initialize a new instance of the cache application.
Refer to dapp.h for definitions of these messages and other
data structures and values used in both the cache applications
and data generator.
Common Structure
================
The basic structure of each application is as follows:
- main program. Declares some variables, call initialize,
and then loop to perform the main task of that application
- initialize. Set up an exit handler (cleanup) and then
call each init routine in order.
- cleanup. Based on flags / other conditions, clean up
execution of the application.
- status. Based on the first parameter, will print a
(hopefully) helpful message.
- nonblock. Windows and Unix implement non blocking
sockets in a different manner; this function hides those
implementation details.
Other lower level routines are basically specific to each
application and described under each program file.
Data generator (dgen.c)
=======================
Maintains a linked list of active connections (caches is
the head pointer). While there is at least one active connection,
accepts new connections, then traverses the list of active
connections. For each active connection, send data. If error
remove the connection from the list. When all messages are
sent, prints a message indicating the data sent and then
waits a second. If there are no active connections, exit the
program.
The function init_socket creates a connection socket, binds
it to the data generator port (accept all hosts), and sets
up to listen for new connections. The accept in this function
blocks, waiting for a cache application to connect. At this
point, the connection socket is set to non blocking.
The function init_cache adds the provided socket to the
list of active connections. The socket is set to be
non blocking.
The function accept_socket does an accept; most of the time
this fails (no waiting connections) and returns immediately.
If it succeeds, the connection is added to the list using
init_cache.
Data caching application (dcache.c)
===================================
This application has a single command line parameter,
the name of the computer to connect to. This is converted
to an IP address for use in try_cache and/or init_socket.
The main loop of the data cache will block, waiting for
the next message from the data generator. On errors, the
program will exit. Otherwise, a sequence check is done,
the cache is updated, and a message printed to show the
transfers are in sync with the data generator. The final
step in the loop is to check for further connections.
The init_socket function tries to connect with a cache
application (calling try_cache) and then connects to the
data generator. If the data cache application is run
before the data generator is active, it will try again
after a 10 second delay.
The try_cache function tries to connect to a cache
application. If a connection is made, it reads the
message to update the sequence / remote address, then
reads the cached data and fills the local copy of the
cache (printing for each message). If no connection is
made, the program closes the socket & returns (go
directly to the data generator).
The init_csocket function sets up a connection socket
in a manner similar to dgen's init_socket. The main
difference is that this will set the socket non blocking
right away and not wait for a connection.
The handle_cache function checks for another data cache
on the connection socket. If none, returns immediately.
If a connection is available, sends the messages read
by try_cache [in the other copy of the caching application].
Other Notes / Lessons Learned
=============================
If you run more than one copy of the data cache application
on a PC, the first will handle all cache connections but
all copies will process messages from the data generator.
If the first copy fails, another cache application will
pick up further cache connections after the TCP time out
(about 1 minute) occurs. This can aid in failure recovery
and in testing using a single system.
As mentioned above, the data being exchanged between systems
can be changed to have more information. In that case, the
simple assignment should be replaced with a call to memcpy
or a similar block copy operation.
As a further improvement, the code that is shared between
the data generator and cache applications should be put
into a separate compilation unit to reduce the size and
aid in maintenance.
The BSD Unix implementation of sockets is the common
parent for both MS Windows and most Unix implementations
of sockets. However there has been a number of chagnes on
both platforms, and it is not so easy to produce an
application that compiles and runs on both platforms.
The number of #if constructs in the code illustrates that.
----- dgen.c -----
/*
* dgen.c -- distributed data generator
*/
/* system includes */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <sys/types.h>
/*
* conditional compile for Unix / Windows differences
*/
#if defined(_WIN32)
#include <windows.h>
#include <winsock.h>
static WSADATA WSAData;
static SOCKET conn_socket = INVALID_SOCKET;
#define CLSOCK closesocket
#define MYDELAY Sleep(1000)
#elif defined(__GNUC__)
/* above should probably be a posix declaration */
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <unistd.h>
#include <fcntl.h>
static int conn_socket = 0; /* connection socket number */
#define CLSOCK close
#define MYDELAY sleep(1)
#else
#error "Not set up for this system type, please fix the code"
#endif
#include "dapp.h"
static char *pname; /* name of this application */
static int my_port = DPORT; /* tcp port connection */
static int flag_conn = 0; /* have connection socket */
static struct data_cache the_source; /* the master copy of data */
/* note - sequence used on data generator to count cycles / set slots
*/
struct rbuff;
struct rbuff {
struct rbuff *next;
int cache_socket;
int seq;
};
static struct rbuff *caches;
/*************************************************************
* helper to dump error messages
* pass retval back for use in if statement
*************************************************************/
int status(int retval,
char *level,
char *what,
char *where)
{
if (retval)
{
fprintf(stderr, "%s: %s - %s failed in %s\n",
pname, level, what, where);
perror(pname);
}
return retval;
}
/*************************************************************
* helper to handle nasty non-blocking I/O set up
*************************************************************/
void nonblock(int fd)
{
#if defined(WIN32)
u_long flag = 1;
if (status((ioctlsocket(fd, FIONBIO, &flag) == -1),
"ERROR", "non-blocking I/O", "nonblock"))
exit(EXIT_FAILURE);
#else
int flags = fcntl(fd, F_GETFL, 0);
flags |= O_NONBLOCK|O_NDELAY;
if (status((fcntl(fd, F_SETFL, flags) == -1),
"ERROR", "non-blocking I/O", "nonblock"))
exit(EXIT_FAILURE);
#endif
}
/*************************************************************
* clean up the application
*************************************************************/
void cleanup( void )
{
if (flag_conn)
(void)CLSOCK(conn_socket); /* ignore errors */
#if defined(_WIN32)
WSACleanup();
#endif
}
/*************************************************************
* establish the socket connection
* return value is the socket to the first reader
*************************************************************/
int init_socket()
{
struct sockaddr_in my_sockdata;
int my_sockdata_len = sizeof(my_sockdata);
int retval;
int cache_socket = 0;
conn_socket = socket(PF_INET, SOCK_STREAM, 0);
if (status((conn_socket < 0), "ERROR", "socket", "init_socket"))
exit(EXIT_FAILURE);
flag_conn++;
memset (&my_sockdata, 0, sizeof(my_sockdata));
my_sockdata.sin_family = AF_INET;
my_sockdata.sin_port = htons(my_port);
my_sockdata.sin_addr.s_addr = htonl(INADDR_ANY);
retval = bind (conn_socket, (struct sockaddr*) &my_sockdata,
sizeof(my_sockdata));
if (status(retval, "ERROR", "bind", "init_socket"))
exit(EXIT_FAILURE);
retval = listen (conn_socket, 1); /* listen for one at a time */
if (status(retval, "ERROR", "listen", "init_socket"))
exit(EXIT_FAILURE);
/* this will block - don't bother with data generation until
* we have a cache reading application */
cache_socket = accept (conn_socket, (struct sockaddr*) &my_sockdata,
&my_sockdata_len);
retval = (cache_socket < 0);
if (status(retval, "ERROR", "accept", "init_socket"))
exit(EXIT_FAILURE);
/* at this point, mark the accept socket as non blocking */
nonblock(conn_socket);
return cache_socket;
}
/*************************************************************
* initialize the socket to the cache system
*************************************************************/
void init_cache(int cache_socket)
{
struct rbuff *buf;
buf = (struct rbuff*)calloc(1, sizeof(struct rbuff));
if (status((buf==NULL), "ERROR", "calloc", "init_cache"))
exit(EXIT_FAILURE);
/* insert this buffer into the cache list */
buf->next = caches;
buf->seq = 0;
buf->cache_socket = cache_socket;
caches = buf;
nonblock(cache_socket);
}
/*************************************************************
* initialize the application
* register the exit procedure
* handle command line arguments
* get the socket
*************************************************************/
void initialize(int argc,
char *argv[])
{
int cache_socket;
#if defined (_WIN32)
int retval;
#endif
if (status(atexit(cleanup), "ERROR", "atexit", "initialize"))
exit(EXIT_FAILURE);
/* capture program name */
pname = argv[0];
#if defined(_WIN32)
/* initialize the WinSock DLL (version 1.1) */
retval = WSAStartup (0x0101, &WSAData);
if (retval != 0)
{
fprintf(stderr, "dtest: WSAStartup failed\n");
perror("dtest");
exit(EXIT_FAILURE);
}
#endif
cache_socket = init_socket();
init_cache(cache_socket);
the_source.sequence = 0; /* never sent any data */
}
/*************************************************************
* accept additional connections
*************************************************************/
void accept_socket() {
struct sockaddr_in my_sockdata;
int my_sockdata_len = sizeof(my_sockdata);
int cache_socket = 0;
/* this will not block - continue on any error */
cache_socket = accept (conn_socket, (struct sockaddr*) &my_sockdata,
&my_sockdata_len);
if (cache_socket > 0)
init_cache(cache_socket);
}
int main (int argc,
char * argv[])
{
struct rbuff *next;
struct rbuff *last;
struct rbuff *temp;
struct data_buffer buff;
time_t its_now;
int bytes;
initialize(argc, argv);
/* keep sending data - until all readers are gone */
while (caches != NULL) {
accept_socket();
next = caches;
last = NULL;
its_now = time(NULL);
the_source.times[the_source.sequence % SLOTS] = its_now;
while (next != NULL) {
buff.sequence = the_source.sequence;
buff.slot = the_source.sequence % SLOTS;
buff.now = its_now;
/* note - not blocking send */
bytes = send(next->cache_socket, (char *)&buff,
sizeof(struct data_buffer), 0);
if (bytes <= 0)
{ /* we have lost connection with the destination */
/* remove this item from the linked list */
if (last == NULL)
{
/* fprintf(stdout, "head - caches:%p, next:%p,
next->next:%p\n", */
/* caches, next, next->next); */
caches = next->next;
}
else
{
/* fprintf(stdout, "mid - last:%p, next:%p, next->next:%p\n",
*/
/* last, next, next->next); */
last->next = next->next;
}
/* close the socket, release memory & bump to next list item */
(void)CLSOCK(next->cache_socket);
temp = next;
next = next->next;
(void)free(temp);
}
else
{
last = next;
next = next->next;
}
}
/* have sent all the messages to the other systems */
/* print a message, check the connect socket & delay a moment */
/* note that ctime returns string w/ new line */
fprintf(stdout, "%s: Seq #%d, time is %s",
pname, the_source.sequence, ctime(&its_now));
the_source.sequence++;
MYDELAY;
}
return EXIT_SUCCESS;
}
----- dcache.c -----
/*
* dcache.c -- distributed cache application
*/
/* system includes */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <sys/types.h>
/*
* conditional compile for Unix / Windows differences
*/
#if defined(_WIN32)
#include <windows.h>
#include <winsock.h>
static WSADATA WSAData;
static SOCKET my_socket = INVALID_SOCKET;
static SOCKET conn_socket = INVALID_SOCKET;
static u_long remote_addr = 0; /* address of remote host */
#define CLSOCK closesocket
#define MYDELAY Sleep(10000)
#elif defined(__GNUC__)
/* above should probably be a posix declaration */
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <unistd.h>
#include <fcntl.h>
static int my_socket = 0; /* connection socket number */
static int conn_socket = 0; /* cache socket number */
static u_int32_t remote_addr = 0; /* address of remote host */
#define CLSOCK close
#define MYDELAY sleep(10)
#else
#error "Not set up for this system type, please fix the code"
#endif
#include "dapp.h"
static char *pname; /* name of this application */
static int flag_tcp = 0; /* link connected if non zero */
static int flag_conn = 0; /* cache socket up if non zero */
static int my_port = DPORT; /* tcp port connection */
static int c_port = CPORT; /* cache port connection */
static struct data_cache my_cache;
static struct dgen_buffer my_dgen;
/*************************************************************
* helper to dump error messages
* pass retval back for use in if statement
*************************************************************/
int status(int retval,
char *level,
char *what,
char *where)
{
if (retval)
{
fprintf(stderr, "%s: %s - %s failed in %s\n",
pname, level, what, where);
perror(pname);
}
return retval;
}
/*************************************************************
* helper to handle nasty non-blocking I/O set up
*************************************************************/
void nonblock(int fd)
{
#if defined(WIN32)
u_long flag = 1;
if (status((ioctlsocket(fd, FIONBIO, &flag) == -1),
"ERROR", "non-blocking I/O", "nonblock"))
exit(EXIT_FAILURE);
#else
int flags = fcntl(fd, F_GETFL, 0);
flags |= O_NONBLOCK|O_NDELAY;
if (status((fcntl(fd, F_SETFL, flags) == -1),
"ERROR", "non-blocking I/O", "nonblock"))
exit(EXIT_FAILURE);
#endif
}
/*************************************************************
* clean up the application
*************************************************************/
void cleanup( void )
{
#if defined(_WIN32)
WSACleanup();
#endif
}
/*************************************************************
* try connecting to a cache machine
*************************************************************/
void try_cache()
{
int retval;
struct sockaddr_in my_sockdata;
struct data_buffer buff;
int bytes;
my_socket = socket(PF_INET, SOCK_STREAM, 0);
retval = (my_socket < 0);
if (status(retval, "ERROR", "socket", "init_socket"))
exit(EXIT_FAILURE);
/* establish the connection */
memset (&my_sockdata, 0, sizeof(my_sockdata));
my_sockdata.sin_family = AF_INET;
my_sockdata.sin_port = htons(c_port);
my_sockdata.sin_addr.s_addr = remote_addr;
retval = connect(my_socket, (struct sockaddr*) &my_sockdata,
sizeof(my_sockdata));
if (retval == 0)
{
/* get data generator information */
bytes = recv(my_socket, (char *)&my_dgen,
sizeof(struct dgen_buffer), 0);
remote_addr = my_dgen.remote_addr; /* point to data generator */
my_cache.sequence = my_dgen.sequence; /* first time alignment */
fprintf(stdout, "%s: loading cache with Seq #%d\n",
pname, my_cache.sequence);
/* now get the data already sent out */
while (1)
{
/* blocking read */
bytes = recv(my_socket, (char *)&buff,
sizeof(struct data_buffer), 0);
if (bytes <= 0)
break; /* lost connection, exit */
my_cache.times[buff.slot] = buff.now;
my_cache.slot = buff.slot;
fprintf(stdout, "%s: Seq #%d, time is %s",
pname, buff.sequence, ctime(&buff.now));
}
}
/* else */
/* perror(pname); */
/* else do nothing */
CLSOCK(my_socket); /* socket no longer needed - close it */
/* now will connect to data generator directly */
}
/*************************************************************
* establish the socket connection
*************************************************************/
void init_socket()
{
int retval;
struct sockaddr_in my_sockdata;
try_cache();
while (1)
{
my_socket = socket(PF_INET, SOCK_STREAM, 0);
retval = (my_socket < 0);
if (status(retval, "ERROR", "socket", "init_socket"))
exit(EXIT_FAILURE);
/* establish the connection */
memset (&my_sockdata, 0, sizeof(my_sockdata));
my_sockdata.sin_family = AF_INET;
my_sockdata.sin_port = htons(my_port);
my_sockdata.sin_addr.s_addr = remote_addr;
retval = connect(my_socket, (struct sockaddr*) &my_sockdata,
sizeof(my_sockdata));
if (retval == 0)
break; /* success */
else
{
CLSOCK(my_socket); /* socket unusable - close it */
fprintf(stderr,
"%s: STATUS - ECONNREFUSED, retry in 10 seconds.\n",
pname);
perror(pname);
MYDELAY;
}
}
flag_tcp++; /* note connection established */
}
/*************************************************************
* establish the cache socket connection
* set non blocking and will accept in main loop
*************************************************************/
void init_csocket()
{
struct sockaddr_in my_sockdata;
int my_sockdata_len = sizeof(my_sockdata);
int retval;
conn_socket = socket(PF_INET, SOCK_STREAM, 0);
if (status((conn_socket < 0), "ERROR", "socket", "init_socket"))
exit(EXIT_FAILURE);
memset (&my_sockdata, 0, my_sockdata_len);
my_sockdata.sin_family = AF_INET;
my_sockdata.sin_port = htons(c_port);
my_sockdata.sin_addr.s_addr = htonl(INADDR_ANY);
retval = bind (conn_socket, (struct sockaddr*) &my_sockdata,
my_sockdata_len);
if (retval)
{ /* port in use, try later */
CLSOCK(conn_socket);
return;
}
retval = listen (conn_socket, 1); /* listen for one at a time */
if (status(retval, "ERROR", "listen", "init_socket"))
exit(EXIT_FAILURE);
/* at this point, mark the accept socket as non blocking */
nonblock(conn_socket);
flag_conn++;
}
/*************************************************************
* initialize the application
* register the exit procedure
* handle command line arguments
* get the socket
*************************************************************/
void initialize(int argc,
char *argv[])
{
int retval;
struct hostent *remote_host;
if (status(atexit(cleanup), "ERROR", "atexit", "initialize"))
exit(EXIT_FAILURE);
/* capture program name */
pname = argv[0];
#if defined(_WIN32)
/* initialize the WinSock DLL (version 1.1) */
retval = WSAStartup (0x0101, &WSAData);
if (retval != 0)
{
fprintf(stderr, "dtest: WSAStartup failed\n");
perror("dtest");
exit(EXIT_FAILURE);
}
#endif
/* get address of remote host */
if (status((argc <= 1), "ERROR", "argc > 1", "initialize"))
exit(EXIT_FAILURE);
remote_host = gethostbyname(argv[1]);
retval = (remote_host == (void *) 0);
if (status(retval, "ERROR", "gethostbyname", "initialize"))
exit(EXIT_FAILURE);
retval = (remote_host->h_length > sizeof(remote_addr));
if (status(retval, "ERROR", "remote address fits", "initialize"))
exit(EXIT_FAILURE);
retval = (remote_host->h_addr_list[0] == (void *)0);
if (status(retval, "ERROR", "remote address valid", "initialize"))
exit(EXIT_FAILURE);
memcpy(&remote_addr, remote_host->h_addr_list[0],
remote_host->h_length);
init_socket();
}
/*************************************************************
* handle_cache - accept connection & send cache data
*************************************************************/
void handle_cache()
{
struct sockaddr_in my_sockdata;
int my_sockdata_len = sizeof(my_sockdata);
int cache_socket = 0;
int i;
int j = my_cache.sequence-SLOTS; /* oldest sequence number */
int k = (1+my_cache.slot)%SLOTS; /* oldest slot */
struct data_buffer buff;
int bytes;
cache_socket = accept (conn_socket, (struct sockaddr*) &my_sockdata,
&my_sockdata_len);
if (cache_socket > 0)
{
my_dgen.sequence = my_cache.sequence;
my_dgen.remote_addr = remote_addr;
bytes = send(cache_socket, (char *)&my_dgen,
sizeof(struct dgen_buffer), 0);
fprintf(stdout, "%s: sending cache \n", pname);
for (i = 0; i<SLOTS; i++) {
if (j>=0)
{
buff.sequence = j++;
buff.slot = k;
buff.now = my_cache.times[buff.slot];
bytes = send(cache_socket, (char *)&buff,
sizeof(struct data_buffer), 0);
}
else
j++;
k = (1+k)%SLOTS;
/* fprintf(stdout, */
/* "%s: send Seq #%d in slot %d, time is %s", */
/* pname, buff.sequence, buff.slot, ctime(&buff.now)); */
}
/* everything is sent, clean up */
(void)CLSOCK(cache_socket);
}
/* else do nothing */
}
/*************************************************************
* main program
*************************************************************/
int main (int argc,
char * argv[])
{
struct data_buffer buff;
int bytes;
initialize(argc, argv);
while (1)
{
/* blocking read */
bytes = recv(my_socket, (char *)&buff,
sizeof(struct data_buffer), 0);
if (bytes <= 0)
break; /* lost connection, exit */
if (my_cache.sequence == 0)
my_cache.sequence = buff.sequence; /* first time alignment */
if (status((my_cache.sequence++ != buff.sequence),
"ERROR", "sequence mismatch", "main"))
{
fprintf(stderr, "%s: expected %d, received %d\n",
pname, my_cache.sequence, buff.sequence);
exit(EXIT_FAILURE);
}
my_cache.times[buff.slot] = buff.now;
my_cache.slot = buff.slot;
fprintf(stdout, "%s: Seq #%d, time is %s",
pname, buff.sequence, ctime(&buff.now));
/* allow another machine to connect */
if (flag_conn)
handle_cache();
else
init_csocket();
}
return EXIT_SUCCESS;
}
----- Makefile ----- (for building on a Unix system)
CFLAGS=-g -O2 -Wall
all : dgen dcache dtest
dgen.o : dgen.c dapp.h
dgen : dgen.o
dcache.o : dcache.c dapp.h
dcache : dcache.o
dtest : dtest.o
dtest.o : dtest.c
----- End of Answer ----- |
Request for Answer Clarification by
questionboy-ga
on
06 May 2003 23:26 PDT
Hello, Manaic:
After I run the answer of the program, the dgen.c is fine, but there
are some errors in dcache.c. This is the result:
--------------------Configuration: dcache - Win32 Debug------
Compiling...
dcache.cpp
D:\dnet\dcache\dcache.cpp(50) : error C2065: 'CPORT' : undeclared
identifier
D:\dnet\dcache\dcache.cpp(52) : error C2079: 'my_dgen' uses undefined
struct 'dgen_buffer'
D:\dnet\dcache\dcache.cpp(131) : error C2027: use of undefined type
'dgen_buffer'
D:\dnet\dcache\dcache.cpp(52) : see declaration of
'dgen_buffer'
D:\dnet\dcache\dcache.cpp(132) : error C2027: use of undefined type
'dgen_buffer'
D:\dnet\dcache\dcache.cpp(52) : see declaration of
'dgen_buffer'
D:\dnet\dcache\dcache.cpp(132) : error C2228: left of '.remote_addr'
must have class/struct/union type
D:\dnet\dcache\dcache.cpp(133) : error C2027: use of undefined type
'dgen_buffer'
D:\dnet\dcache\dcache.cpp(52) : see declaration of
'dgen_buffer'
D:\dnet\dcache\dcache.cpp(133) : error C2228: left of '.sequence' must
have class/struct/union type
D:\dnet\dcache\dcache.cpp(145) : error C2039: 'slot' : is not a member
of 'data_cache'
d:\dnet\dcache\dapp.h(30) : see declaration of 'data_cache'
D:\dnet\dcache\dcache.cpp(293) : error C2039: 'slot' : is not a member
of 'data_cache'
d:\dnet\dcache\dapp.h(30) : see declaration of 'data_cache'
D:\dnet\dcache\dcache.cpp(301) : error C2027: use of undefined type
'dgen_buffer'
D:\dnet\dcache\dcache.cpp(52) : see declaration of
'dgen_buffer'
D:\dnet\dcache\dcache.cpp(301) : error C2228: left of '.sequence' must
have class/struct/union type
D:\dnet\dcache\dcache.cpp(302) : error C2027: use of undefined type
'dgen_buffer'
D:\dnet\dcache\dcache.cpp(52) : see declaration of
'dgen_buffer'
D:\dnet\dcache\dcache.cpp(302) : error C2228: left of '.remote_addr'
must have class/struct/union type
D:\dnet\dcache\dcache.cpp(304) : error C2027: use of undefined type
'dgen_buffer'
D:\dnet\dcache\dcache.cpp(52) : see declaration of
'dgen_buffer'
D:\dnet\dcache\dcache.cpp(357) : error C2039: 'slot' : is not a member
of 'data_cache'
d:\dnet\dcache\dapp.h(30) : see declaration of 'data_cache'
Error executing cl.exe.
dcache.exe - 15 error(s), 0 warning(s)
*************************************************
Also, could you teache me how to create the Makefile in visual C++
Thanks a lot
|
Clarification of Answer by
maniac-ga
on
07 May 2003 05:05 PDT
Hello Questionboy,
Sigh. I forgot to include the updated header file. See below.
About Makefiles, the concept is quite simple. Using a few lines from
the one I supplied for an example: [with comments inserted to describe
what happens]
CFLAGS=-g -O2 -Wall
[define a variable, in this case CFLAGS, to be equal to the string on
the right side of the equals sign. The default actions of make use
this variable on all C compiles. There are similar variables for other
compilers (e.g,. for C++); check the documentation that comes with
make for details.]
all : dgen dcache dtest
[The "first" action is the default taken when you run
make
In this first action, I say to create a file named "all", I need to
have files dgen, dcache, and dtest. Make will then look for rules to
build those before doing this action. If I had provided a set of
commands on the lines after this one (preceed by a tab character),
those commands would then be executed after those other files were
built.]
dgen.o : dgen.c dapp.h
[Here, I say that dgen.o depends on the files dgen.c and dapp.h. Since
I don't specify a command, and make has a default action; that default
action is taken. In this case, the command line generated is something
like
cc -g -O2 -Wall -c -o dgen.o dgen.c
which includes the CFLAGS I specified and uses the first C file to
compile. Note that the CFLAGS for gcc may be different than those you
would use for Visual C++]
dgen : dgen.o
[Here I say that dgen depends on the file dgen.o. Again, the default
action is taken which is
cc dgen.o -o dgen
to build the dgen application. I could have defined a variable (but
didn't) to revise the action taken in this case as well.]
From this information and a command line such as:
make dgen
make will look at the modified files and take the steps necessary to
build dgen.
I suggest starting with something simple, see what it does, and
improve it in an incremental manner.
--Maniac
----- dapp.h -----
/*
* dapp.h -- header file for distributed generator / cache application
*/
#ifndef __DAPP
/* TCP port number to use */
#define DPORT 2525
#define CPORT 2526
#define SLOTS 10
/*
* data_buffer
* sequence - sequence number for validity check
* slot - a slot number, increases each pass modulo SLOTS
* now - the time in seconds
*/
struct data_buffer {
int sequence;
int slot;
time_t now;
};
/*
* data_cache
* sequence - last sequence number
* times - the times collected
* to generalize the cache, replace the array with a structure type
*/
struct data_cache {
int sequence;
int slot;
time_t times[SLOTS];
};
/*
* dgen_buffer
* sequence - last sequence number from data generator
* remote_addr - host number of data generator
* Note: may have a problem if running with mixed platforms
* with size of remote_addr (both should be 32 bit unsigned)
*/
struct dgen_buffer {
int sequence;
#if defined(_WIN32)
u_long remote_addr;
#else
u_int32_t remote_addr;
#endif
};
#define __DAPP
#endif
|
Request for Answer Clarification by
questionboy-ga
on
07 May 2003 10:04 PDT
Hello, Manaic:
The dgen and dcache are fine. However, I still don't understand how to
create Makefile. Do I need the Makefile? If not, I will skip it.
I created a txt file named Makefile. Is it right or not. Or I should
do something in console window.
In the answer part, you said:
- a Makefile that can be used on Unix systems to build the
application (I assume you already have suitable project file(s) for
Visual C++)
but I don't have suitable project file for visual C++
|
Clarification of Answer by
maniac-ga
on
07 May 2003 10:28 PDT
Hello Questionboy,
You don't *need* a Makefile. It is one of the first files I write
since the tools I use support it. I provide it as an aid in case you
ever get the application on a Unix system and need to rebuild it. On a
Unix system, with the appropriate development tools you can put all
the files I provided into a directory and then type
make
in a console window and the applications will be built.
You certainly don't need the Makefile for building the applications
(dgen, dcache) with Visual C++ - you have certainly demonstrated that
with your responses.
--Maniac
|
Request for Answer Clarification by
questionboy-ga
on
07 May 2003 11:50 PDT
Hello, Manaic:
my outputs are:
D:\dnet\dgen\Debug>dgen
dgen: Seq #0, time is Wed May 07 13:11:23 2003
dgen: Seq #1, time is Wed May 07 13:11:24 2003
dgen: Seq #2, time is Wed May 07 13:11:25 2003
dgen: Seq #3, time is Wed May 07 13:11:26 2003
dgen: Seq #4, time is Wed May 07 13:11:27 2003
dgen: Seq #5, time is Wed May 07 13:11:28 2003
dgen: Seq #6, time is Wed May 07 13:11:29 2003
dgen: Seq #7, time is Wed May 07 13:11:30 2003
dgen: Seq #8, time is Wed May 07 13:11:32 2003
dgen: Seq #9, time is Wed May 07 13:11:33 2003
dgen: Seq #10, time is Wed May 07 13:11:34 2003
=======================================================
=======================================================
D:\dnet\dcache\Debug>dcache localhost
dcache: Seq #0, time is Wed May 07 13:11:23 2003
dcache: Seq #1, time is Wed May 07 13:11:24 2003
dcache: Seq #2, time is Wed May 07 13:11:25 2003
dcache: Seq #3, time is Wed May 07 13:11:26 2003
dcache: Seq #4, time is Wed May 07 13:11:27 2003
dcache: sending cache
dcache: Seq #5, time is Wed May 07 13:11:28 2003
dcache: Seq #6, time is Wed May 07 13:11:29 2003
=====================================================
=====================================================
D:\dnet\dcache\Debug>dcache localhost
dcache: loading cache with Seq #5
dcache: Seq #0, time is Wed May 07 13:11:23 2003
dcache: Seq #1, time is Wed May 07 13:11:24 2003
dcache: Seq #2, time is Wed May 07 13:11:25 2003
dcache: Seq #3, time is Wed May 07 13:11:26 2003
dcache: Seq #4, time is Wed May 07 13:11:27 2003
dcache: Seq #5, time is Wed May 07 13:11:28 2003
dcache: Seq #6, time is Wed May 07 13:11:29 2003
===================================================
are they correct?
|
Clarification of Answer by
maniac-ga
on
07 May 2003 14:28 PDT
Hello Questionboy,
The results you provided certainly look good to me. It demonstrates:
- data generator sending data to first cache application
- first cache application sending the second second cache application
its data (Seq # 0 through 4); this output should have appeared "all at
once" instead of spaced w/ 1 second pauses between each output
- data from the generator going to both cache applications (Seq # 5
and 6); a one second pause between each value
- all values are consistent (for the same sequence number, the time
is "the same" in all applications)
Those are all "good things" to see from the applications - it
basically means they did what they were supposed to.
You did provide more output from the data generator than the two cache
applications. That may be as expected - let me explain.
On my system, if you stop the data generator before the cache
applications, all stop with the same sequence number. If you stop the
cache applications before the data generator, the data generator may
produce an additional message (or a few) before it gets the error
status and stops sending data and quits. If this output was the latter
case - the output you provided is as expected.
If the cache applications "just died" without any message after
sequence #6, that would be something I have not seen. If so, let me
know so we can follow up w/ some debug ideas. In particular, you might
try to...
- make a copy of dcache.c (call it something like dread.c)
- in dread.c, take out
if (flag_conn)
handle_cache();
else
init_csocket();
from the end of the main procedure. You could also remove the
functions handle_cache and init_csocket from dread.c as well.
Build a third application (named dread) from dread.c and dapp.h. Run
the programs in the order
dgen
dcache localhost
dread localhost
If this works, it means that the Windows machine is having problems
with the second connection to the socket port used by the cache
application [sigh]. It would also mean you have a limitation that only
one cache application can run per system (but you could run many
reader applications).
--Maniac
|
Request for Answer Clarification by
questionboy-ga
on
07 May 2003 17:11 PDT
Hello Maniac:
I created the dread, and did what you suggested. Those are output:
================================================
D:\dnet\dgen\Debug>dgen
dgen: Seq #0, time is Wed May 07 19:58:17 2003
dgen: Seq #1, time is Wed May 07 19:58:18 2003
dgen: Seq #2, time is Wed May 07 19:58:19 2003
dgen: Seq #3, time is Wed May 07 19:58:20 2003
dgen: Seq #4, time is Wed May 07 19:58:21 2003
================================================
D:\dnet\dcache\Debug>dcache localhost
dcache: Seq #0, time is Wed May 07 19:58:17 2003
dcache: Seq #1, time is Wed May 07 19:58:18 2003
dcache: Seq #2, time is Wed May 07 19:58:19 2003
dcache: sending cache
dcache: Seq #3, time is Wed May 07 19:58:20 2003
dcache: Seq #4, time is Wed May 07 19:58:21 2003
=================================================
D:\dnet\dread\Debug>dread localhost
dread: loading cache with Seq #3
dread: Seq #0, time is Wed May 07 19:58:17 2003
dread: Seq #1, time is Wed May 07 19:58:18 2003
dread: Seq #2, time is Wed May 07 19:58:19 2003
dread: Seq #3, time is Wed May 07 19:58:20 2003
dread: Seq #4, time is Wed May 07 19:58:21 2003
=================================================
-Should I use the dgen, dcache, and dread, or use original dgen and dcache?
-If I want to run on two computer, how should I do?
|
Clarification of Answer by
maniac-ga
on
07 May 2003 19:36 PDT
Hello Questionboy,
If dread doesn't help - I would not use it; use dgen and dcache
instead. Apparently the problem I thought might occur was not there.
Just to see if something else might be a problem...
[1] What happens if you let the data generator and cache application
just run for a few minutes (say 5-10)? They do continue to run without
any problem - right? [I don't need to see this output]
[2] After doing #1, then start another copy of dcache. I want to
confirm the second start is causing the problem.
It might also be a good idea to look at the result of WSAGetLastError
in the main program. Change line 345 (or so) of dcache.c from
break;
to read
{
fprintf(stdout, "%s: error is %d", pname, WSAGetLastError());
break;
}
and then look up the error code in winsock.h. That may provide a lead.
About running on two computers. I see a few things you need to do for
this:
- find out the IP host name or IP address of the computer that will
run the data generator. You should be able to look this up in one of
the control panels (network and dial up connections?). It should be a
property setting. I also found a reference indicating that a command
window program named ipconfig may also give you this information.
If it is an IP address, it will look like four numbers w/ dots between
them (e.g., 206.17.136.174). The host name is *not* necessarily the
name of your machine in a Windows domain.
- get a copy of dcache copied to the second machine. I'll assume the
second machine has a copy of the correct DLL's. Alternatively, copy
the source files & build the executable programs on the second
machine.
- you need a console window on each machine
I'd still start dgen first and then the cache application (on separate
machines). Something like
dgen
on the first machine and
dcache 206.17.136.174
on the second machine (or use the host name if you have it). If you
get the address wrong on my system, the dcache program just sits there
(no output). The output should look the same as if you are using a
single system.
Another good test if you run on two machines is to
1 - run dgen on machine #1
2 - run dcache on machine #2 (using the address of #1)
3 - run dcache on machine #1 (using the address of #2)
and see if *that* combination works OK. Then I would also try
1 - run dgen on machine #1
2 - run dcache on machine #1 (using the address of #1)
3 - run dcache on machine #2 (using the address of #2)
These would help to isolate the problem to be concurrent use of the
cache applications on the single machine (or something else).
--Maniac
|