Sockets in gfortran?

  • Follow


Is there a way to program socket communications in gfortran on Windows?  I'm 
guessing that this can be achieved via gcc, so a better question might be has 
someone seen or developed Fortran code to handle sockets via C?
0
Reply Gib 8/30/2010 9:02:35 AM

On 30 aug, 11:02, Gib Bogle <g.bo...@auckland.no.spam.ac.nz> wrote:
> Is there a way to program socket communications in gfortran on Windows? =
=A0I'm
> guessing that this can be achieved via gcc, so a better question might be=
 has
> someone seen or developed Fortran code to handle sockets via C?

It is certainly doable. I did something in that direction in a work-
related
project (not with gcc/gfortran though). I have been meaning to do such
a module
for my Flibs project (flibs.sf.net), but have not gotten around to it.

Regards,

Arjen
0
Reply Arjen 8/30/2010 11:32:51 AM


On Aug 30, 12:02=A0pm, Gib Bogle <g.bo...@auckland.no.spam.ac.nz> wrote:
> Is there a way to program socket communications in gfortran on Windows? =
=A0I'm
> guessing that this can be achieved via gcc, so a better question might be=
 has
> someone seen or developed Fortran code to handle sockets via C?

I saw some code here http://genepi.qimr.edu.au/staff/davidD/, but I
never tried it myself.
Victor.
0
Reply Victor 8/30/2010 5:03:02 PM

Gib Bogle <g.bogle@auckland.no.spam.ac.nz> wrote:

> Is there a way to program socket communications in gfortran on Windows?  I'm
> guessing that this can be achieved via gcc, so a better question might be has
> someone seen or developed Fortran code to handle sockets via C?

Here's some stuff I did some time ago. The Unix version was from about
to 2 decades ago and I did a Windows port about a decade later. This was
specifically done for CVF, but I doubt there would be much if any
difference for other Windows Fortran compilers.

The stuff attached here is just the C wrappers that make the socket
stuff reasonably callable from Fortran. It is pretty simple minded;
there's a tcp_connect, tcp_close, tcp_read, and tcp_write. This is all
from before f2003 C interop (as mentioned, the original Unix versions
date back 2 decades).

The tcp_connect is just for the client end. My server was always on a
Unix box, so I didn't need to do the server-side stuff for Windows.

/* $Id: clientc.c,v 1.1.1.1 2003/03/06 19:38:16 maine Exp $ */
/* $Name:  $ */

/* clientc.c
 * open a tcp connection for a getData client.
 *
 * The read/write/close routines are used in both clients and servers
 * and are in a separate file.
 *
 * This file has wrappers for the system routines that are
 * not directly or easily callable from Fortran.
 * Specific to system Fortran and C calling conventions.
 *
 * Version for MS Windows MS C and CVF.
 * Differences from nag version are:
 *   Different system include files.
 *   Different procedure name mangling convention in the defines
 *   Specify __stdcall in procedure headers.
 *   Add extern decl for write_error_sub (to get the __stdcall).
 *   Different placement of implicit string length argument.
 *   Have to call Win-specific WSAStartup or nothing works.
 *   Cast *port (perhaps appropriate for nag version also).
 *   Used SOCKET_ERROR and INVALID_SOCKET to test for errors per MS
docs,
 *     though the bsd-style test did appear to work.
 *
 * 11 Oct 91, Richard Maine: Version 1.0
 * 17 Jul 01, Richard Maine: MS Windows port.
 */

#include <sys/types.h>
#include <winsock.h>

/* Defines to make routines fortran-callable */
/*
 * Would probably be better to return an error message to the
 * calling routine instead of calling write_error_msg from in here.
 */

static int started = 0;

#define write_error_msg WRITE_ERROR_SUB
#define tcp_connect TCP_CONNECT
extern __stdcall WRITE_ERROR_SUB (char * msg, int n);

/* Wrapper to call fortran error message routine.
 * We want to avoid standard c i/o. */

void printerrormsg(msg)
  char *msg;
{
  write_error_msg(msg,strlen(msg));
}


/* Connect to a specified host and port.
 * Return a socket number in sock. */

void __stdcall tcp_connect(sock, host_name, host_name_len, port, error)
  int *sock, *port, *error;
  char *host_name;
  int host_name_len;
{
  char cstring[129];
  int i;
  struct hostent *host_ent;
  struct sockaddr_in host;
  int keepalive;
  char *from, *to;
  WORD wver;
  WSADATA wsaData;

  *error = 1;

  /* Start up Windows sockets */
  if (started == 0) {
    started = 1;
    wver = MAKEWORD(2,0);
    i = WSAStartup(wver, &wsaData);
  }

  /* Make host_name into a c string */
  for (i=0; (i<host_name_len) && (i<127) && (host_name[i] != ' '); i++)
    cstring[i] = host_name[i];
  cstring[i] = '\0';

  /* Find the host IP address */
  host.sin_family = AF_INET;
  host_ent = gethostbyname(cstring);
  if (host_ent==0) {printerrormsg("Can't find host address."); return;}
  /* Avoid bcopy/memcpy dependence. */
  from = (char *) host_ent->h_addr;
  to = (char *) &host.sin_addr;
  for (i=0; i<host_ent->h_length; i++) *to++ = *from++;

  /* Set the port */
  host.sin_port = htons((unsigned short int) *port);

  /* Create a socket */
  *sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  if (*sock==INVALID_SOCKET) {printerrormsg("Can't create socket.");
return;}

  /* Attempt connection */
  if (connect(*sock, (struct sockaddr *) &host, sizeof(host)) ==
SOCKET_ERROR)
    {printerrormsg("Connect failed."); close(*sock); return;}

  /* Enable keepalive packets to check socket connection. */
  keepalive = 1;
  setsockopt(*sock, SOL_SOCKET, SO_KEEPALIVE, (char *) &keepalive, 4);

  *error = 0;
}


/* $Id: tcpc.c,v 1.1.1.1 2003/03/06 19:38:16 maine Exp $ */
/* $Name:  $ */

/* tcpc.c
 * tcp communication routines for getData.
 *
 * The read/write/close here are used in both clients and servers.
 * These routines must not directly or indirectly reference the
 * fortran write_error_msg routine because some versions of it
 * may call these routines.
 *
 * The routines for opening a tcp connection are different for
 * clients and servers.  Furthermore, the client one may
 * call write_error_msg.  Thus those routines are in separate files.
 *
 * This file has wrappers for the system routines that are
 * not directly or easily callable from Fortran.
 * Specific to system Fortran and C calling conventions.
 *
 * Version for MS Windows MS C and CVF.
 * Differences from nag version are:
 *   Different system include files.
 *   Different procedure name mangling convention in the defines
 *   Specify __stdcall in procedure headers.
 *   Use closesocket instead of close.
 *   Used SOCKET_ERROR to test for errors per MS docs,
 *     though the bsd-style test did appear to work.
 *
 * 11 Oct 91, Richard Maine: Version 1.0
 * 17 Jul 01, Richard Maine: MS Windows port.
 */

#include <winsock.h>

/* Defines to make routines fortran-callable */
#define tcp_close TCP_CLOSE
#define tcp_read TCP_READ
#define tcp_write TCP_WRITE

void __stdcall tcp_close(sock)
  int *sock;
{
  shutdown(*sock,2); /* clears any pending i/o. */
  closesocket(*sock);
}

/* Write to a tcp socket. */
void __stdcall tcp_write(sock, buf, buflen, error)
  int *sock, *buflen, *error;
  char *buf;
{
  int i;

  i = send(*sock,buf,*buflen,0);
  *error = (i == SOCKET_ERROR);
}

/* Read from a tcp socket. */
void __stdcall tcp_read(sock, buf, buflen, error)
  int *sock, *buflen, *error;
  char *buf;
{
  int nleft, nread;
  char *bufptr;

  bufptr = buf;
  nleft = *buflen;
  *error = 1; 

  while (nleft > 0)
    {
      nread = recv(*sock, bufptr, nleft, 0);
      if (nread == SOCKET_ERROR) return;
      nleft -= nread;
      bufptr += nread;
    }

  *error = 0;
}


-- 
Richard Maine                    | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle           |  -- Mark Twain
0
Reply nospam47 (9742) 8/30/2010 5:54:20 PM

Victor Podsechin wrote:
> On Aug 30, 12:02 pm, Gib Bogle <g.bo...@auckland.no.spam.ac.nz> wrote:
>> Is there a way to program socket communications in gfortran on Windows?  I'm
>> guessing that this can be achieved via gcc, so a better question might be has
>> someone seen or developed Fortran code to handle sockets via C?
> 
> I saw some code here http://genepi.qimr.edu.au/staff/davidD/, but I
> never tried it myself.
> Victor.

Hi Victor.  This is Linux/Unix code, and MinGW doesn't like it at all.
0
Reply Gib 8/30/2010 9:02:02 PM

Richard Maine wrote:
> Gib Bogle <g.bogle@auckland.no.spam.ac.nz> wrote:
> 
>> Is there a way to program socket communications in gfortran on Windows?  I'm
>> guessing that this can be achieved via gcc, so a better question might be has
>> someone seen or developed Fortran code to handle sockets via C?
> 
> Here's some stuff I did some time ago. The Unix version was from about
> to 2 decades ago and I did a Windows port about a decade later. This was
> specifically done for CVF, but I doubt there would be much if any
> difference for other Windows Fortran compilers.
> 
> The stuff attached here is just the C wrappers that make the socket
> stuff reasonably callable from Fortran. It is pretty simple minded;
> there's a tcp_connect, tcp_close, tcp_read, and tcp_write. This is all
> from before f2003 C interop (as mentioned, the original Unix versions
> date back 2 decades).
> 
> The tcp_connect is just for the client end. My server was always on a
> Unix box, so I didn't need to do the server-side stuff for Windows.

<code snipped>

Thanks Richard, this will be helpful.
0
Reply Gib 8/30/2010 9:03:10 PM

Hi Richard, a couple of minor mods and this is working with MinGW/gcc/gfortran. 
  No need for __stdcall, or uppercase, but underscores need to be appended to C 
function names.
Thanks a lot.
Gib
0
Reply Gib 8/31/2010 12:47:20 AM

Gib Bogle <g.bogle@auckland.no.spam.ac.nz> wrote:

> Hi Richard, a couple of minor mods and this is working with
> MinGW/gcc/gfortran. No need for __stdcall, or uppercase, but underscores
> need to be appended to C function names.
> Thanks a lot.

You're welcome. Good to hear. I've never actually used MinGW, so I
wasn't at all sure of that part, but it seemed plausible that the native
Windows stuff should be a good starting point.

-- 
Richard Maine                    | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle           |  -- Mark Twain
0
Reply nospam 8/31/2010 1:44:07 AM

Gib Bogle wrote:
> Victor Podsechin wrote:
>> On Aug 30, 12:02 pm, Gib Bogle <g.bo...@auckland.no.spam.ac.nz> wrote:
>>> Is there a way to program socket communications in gfortran on 
>>> Windows?  I'm
>>> guessing that this can be achieved via gcc, so a better question 
>>> might be has
>>> someone seen or developed Fortran code to handle sockets via C?
>>
>> I saw some code here http://genepi.qimr.edu.au/staff/davidD/, but I
>> never tried it myself.
>> Victor.
> 
> Hi Victor.  This is Linux/Unix code, and MinGW doesn't like it at all.

I think you want to start thinking along these lines.  I follow the 
Stevens and Rago development in _Advanced Programming in the Unix 
Environment_.  You can too.  As a matter of fact, you might be a wiz 
with this material relative to me, as I don't have a full year yet as a 
linux user, so I don't really see a lot of the big picture.

http://www.apuebook.com/

The source is free, tested, ... .  There's a chapter on sockets that's 
still way over my head, but there for the download.

if you can get this source running, you can see it done clearly enough 
in C that you can fish out what fortran calls you would issue through 
the iso c binding.

$ gcc  -D_GNU_SOURCE pathfunc.o -Iinclude lib/error.o dir1.c -o out
$ ./out
usage:  ftw  <starting-pathname>
$ ./out /home/dan/source
regular files  =    5541, 86.63 %
directories    =     647, 10.12 %
block special  =       0,  0.00 %
char special   =       0,  0.00 %
FIFOs          =       0,  0.00 %
symbolic links =     208,  3.25 %
sockets        =       0,  0.00 %
$ cat dir1.c
#include "apue.h"
#include <dirent.h>
#include <limits.h>

/* function type that is called for each filename */
typedef	int	Myfunc(const char *, const struct stat *, int);

static Myfunc	myfunc;
static int		myftw(char *, Myfunc *);
static int		dopath(Myfunc *);

static long	nreg, ndir, nblk, nchr, nfifo, nslink, nsock, ntot;

int
main(int argc, char *argv[])
{
	int		ret;

	if (argc != 2)
		err_quit("usage:  ftw  <starting-pathname>");

	ret = myftw(argv[1], myfunc);		/* does it all */

	ntot = nreg + ndir + nblk + nchr + nfifo + nslink + nsock;
	if (ntot == 0)
		ntot = 1;		/* avoid divide by 0; print 0 for all counts */
	printf("regular files  = %7ld, %5.2f %%\n", nreg,
	  nreg*100.0/ntot);
	printf("directories    = %7ld, %5.2f %%\n", ndir,
	  ndir*100.0/ntot);
	printf("block special  = %7ld, %5.2f %%\n", nblk,
	  nblk*100.0/ntot);
	printf("char special   = %7ld, %5.2f %%\n", nchr,
	  nchr*100.0/ntot);
	printf("FIFOs          = %7ld, %5.2f %%\n", nfifo,
	  nfifo*100.0/ntot);
	printf("symbolic links = %7ld, %5.2f %%\n", nslink,
	  nslink*100.0/ntot);
	printf("sockets        = %7ld, %5.2f %%\n", nsock,
	  nsock*100.0/ntot);

	exit(ret);
}

/*
  * Descend through the hierarchy, starting at "pathname".
  * The caller's func() is called for every file.
  */
#define	FTW_F	1		/* file other than directory */
#define	FTW_D	2		/* directory */
#define	FTW_DNR	3		/* directory that can't be read */
#define	FTW_NS	4		/* file that we can't stat */

static char	*fullpath;		/* contains full pathname for every file */

static int					/* we return whatever func() returns */
myftw(char *pathname, Myfunc *func)
{
	int len;
	fullpath = path_alloc(&len);	/* malloc's for PATH_MAX+1 bytes */
									/* ({Prog pathalloc}) */
	strncpy(fullpath, pathname, len);	/* protect against */
	fullpath[len-1] = 0;				/* buffer overrun */

	return(dopath(func));
}

/*
  * Descend through the hierarchy, starting at "fullpath".
  * If "fullpath" is anything other than a directory, we lstat() it,
  * call func(), and return.  For a directory, we call ourself
  * recursively for each name in the directory.
  */
static int					/* we return whatever func() returns */
dopath(Myfunc* func)
{
	struct stat		statbuf;
	struct dirent	*dirp;
	DIR				*dp;
	int				ret;
	char			*ptr;

	if (lstat(fullpath, &statbuf) < 0)	/* stat error */
		return(func(fullpath, &statbuf, FTW_NS));
	if (S_ISDIR(statbuf.st_mode) == 0)	/* not a directory */
		return(func(fullpath, &statbuf, FTW_F));

	/*
	 * It's a directory.  First call func() for the directory,
	 * then process each filename in the directory.
	 */
	if ((ret = func(fullpath, &statbuf, FTW_D)) != 0)
		return(ret);

	ptr = fullpath + strlen(fullpath);	/* point to end of fullpath */
	*ptr++ = '/';
	*ptr = 0;

	if ((dp = opendir(fullpath)) == NULL)	/* can't read directory */
		return(func(fullpath, &statbuf, FTW_DNR));

	while ((dirp = readdir(dp)) != NULL) {
		if (strcmp(dirp->d_name, ".") == 0  ||
		    strcmp(dirp->d_name, "..") == 0)
				continue;		/* ignore dot and dot-dot */

		strcpy(ptr, dirp->d_name);	/* append name after slash */

		if ((ret = dopath(func)) != 0)		/* recursive */
			break;	/* time to leave */
	}
	ptr[-1] = 0;	/* erase everything from slash onwards */

	if (closedir(dp) < 0)
		err_ret("can't close directory %s", fullpath);

	return(ret);
}

static int
myfunc(const char *pathname, const struct stat *statptr, int type)
{
	switch (type) {
	case FTW_F:
		switch (statptr->st_mode & S_IFMT) {
		case S_IFREG:	nreg++;		break;
		case S_IFBLK:	nblk++;		break;
		case S_IFCHR:	nchr++;		break;
		case S_IFIFO:	nfifo++;	break;
		case S_IFLNK:	nslink++;	break;
		case S_IFSOCK:	nsock++;	break;
		case S_IFDIR:
			err_dump("for S_IFDIR for %s", pathname);
					/* directories should have type = FTW_D */
		}
		break;

	case FTW_D:
		ndir++;
		break;

	case FTW_DNR:
		err_ret("can't read directory %s", pathname);
		break;

	case FTW_NS:
		err_ret("stat error for %s", pathname);
		break;

	default:
		err_dump("unknown type %d for pathname %s", type, pathname);
	}

	return(0);
}

// gcc  -D_GNU_SOURCE pathfunc.o -Iinclude lib/error.o dir1.c -o out

$

! end listing of dir1.c

You need 2 other translation units to make this work.  I'll list them 
after the sig.  They're both significant pieces of writing.  pathalloc.c 
and apue.h are what the textbook guys think are the best implementations 
for, respectively, allocating a path and doing anything.

I was very interested the other day to see how steve and james were able 
to make directories using fortran's c bindings.
-- 
Uno

$ cat path_alloc.c
#include "apue.h"
#include <errno.h>
#include <limits.h>

#ifdef	PATH_MAX
static int	pathmax = PATH_MAX;
#else
static int	pathmax = 0;
#endif

#define SUSV3	200112L

static long	posix_version = 0;

/* If PATH_MAX is indeterminate, no guarantee this is adequate */
#define	PATH_MAX_GUESS	1024

char *
path_alloc(int *sizep) /* also return allocated size, if nonnull */
{
	char	*ptr;
	int	size;

	if (posix_version == 0)
		posix_version = sysconf(_SC_VERSION);

	if (pathmax == 0) {		/* first time through */
		errno = 0;
		if ((pathmax = pathconf("/", _PC_PATH_MAX)) < 0) {
			if (errno == 0)
				pathmax = PATH_MAX_GUESS;	/* it's indeterminate */
			else
				err_sys("pathconf error for _PC_PATH_MAX");
		} else {
			pathmax++;		/* add one since it's relative to root */
		}
	}
	if (posix_version < SUSV3)
		size = pathmax + 1;
	else
		size = pathmax;

	if ((ptr = malloc(size)) == NULL)
		err_sys("malloc error for pathname");

	if (sizep != NULL)
		*sizep = size;
	return(ptr);
}

// gcc -c -D_GNU_SOURCE -Iinclude  path_alloc.c -o pathfunc.o
$

$ cd include
$ ls
apue.h
$ cat apue.h
/* Our own header, to be included before all standard system headers */

#ifndef	_APUE_H
#define	_APUE_H

#if defined(SOLARIS)
#define _XOPEN_SOURCE	500	/* Single UNIX Specification, Version 2  for 
Solaris 9 */
#define CMSG_LEN(x)	_CMSG_DATA_ALIGN(sizeof(struct cmsghdr)+(x))
#elif !defined(BSD)
#define _XOPEN_SOURCE	600	/* Single UNIX Specification, Version 3 */
#endif

#include <sys/types.h>		/* some systems still require this */
#include <sys/stat.h>
#include <sys/termios.h>	/* for winsize */
#ifndef TIOCGWINSZ
#include <sys/ioctl.h>
#endif
#include <stdio.h>		/* for convenience */
#include <stdlib.h>		/* for convenience */
#include <stddef.h>		/* for offsetof */
#include <string.h>		/* for convenience */
#include <unistd.h>		/* for convenience */
#include <signal.h>		/* for SIG_ERR */

#define	MAXLINE	4096			/* max line length */

/*
  * Default file access permissions for new files.
  */
#define	FILE_MODE	(S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)

/*
  * Default permissions for new directories.
  */
#define	DIR_MODE	(FILE_MODE | S_IXUSR | S_IXGRP | S_IXOTH)

typedef	void	Sigfunc(int);	/* for signal handlers */

#if	defined(SIG_IGN) && !defined(SIG_ERR)
#define	SIG_ERR	((Sigfunc *)-1)
#endif

#define	min(a,b)	((a) < (b) ? (a) : (b))
#define	max(a,b)	((a) > (b) ? (a) : (b))

/*
  * Prototypes for our own functions.
  */
char	*path_alloc(int *);				/* {Prog pathalloc} */
long	 open_max(void);				/* {Prog openmax} */
void	 clr_fl(int, int);				/* {Prog setfl} */
void	 set_fl(int, int);				/* {Prog setfl} */
void	 pr_exit(int);					/* {Prog prexit} */
void	 pr_mask(const char *);			/* {Prog prmask} */
Sigfunc	*signal_intr(int, Sigfunc *);	/* {Prog signal_intr_function} */

int		 tty_cbreak(int);				/* {Prog raw} */
int		 tty_raw(int);					/* {Prog raw} */
int		 tty_reset(int);				/* {Prog raw} */
void	 tty_atexit(void);				/* {Prog raw} */
#ifdef	ECHO	/* only if <termios.h> has been included */
struct termios	*tty_termios(void);		/* {Prog raw} */
#endif

void	 sleep_us(unsigned int);			/* {Ex sleepus} */
ssize_t	 readn(int, void *, size_t);		/* {Prog readn_writen} */
ssize_t	 writen(int, const void *, size_t);	/* {Prog readn_writen} */
void	 daemonize(const char *);			/* {Prog daemoninit} */

int		 s_pipe(int *);					/* {Progs streams_spipe sock_spipe} */
int		 recv_fd(int, ssize_t (*func)(int,
		         const void *, size_t));/* {Progs recvfd_streams 
recvfd_sockets} */
int		 send_fd(int, int);				/* {Progs sendfd_streams sendfd_sockets} */
int		 send_err(int, int,
		          const char *);		/* {Prog senderr} */
int		 serv_listen(const char *);		/* {Progs servlisten_streams 
servlisten_sockets} */
int		 serv_accept(int, uid_t *);		/* {Progs servaccept_streams 
servaccept_sockets} */
int		 cli_conn(const char *);		/* {Progs cliconn_streams cliconn_sockets} */
int		 buf_args(char *, int (*func)(int,
		          char **));			/* {Prog bufargs} */

int		 ptym_open(char *, int);	/* {Progs3 ptyopen_streams ptyopen_bsd 
ptyopen_linux} */
int		 ptys_open(char *);			/* {Progs3 ptyopen_streams ptyopen_bsd 
ptyopen_linux} */
#ifdef	TIOCGWINSZ
pid_t	 pty_fork(int *, char *, int, const struct termios *,
		          const struct winsize *);		/* {Prog ptyfork} */
#endif

int		lock_reg(int, int, int, off_t, int, off_t); /* {Prog lockreg} */
#define	read_lock(fd, offset, whence, len) \
			lock_reg((fd), F_SETLK, F_RDLCK, (offset), (whence), (len))
#define	readw_lock(fd, offset, whence, len) \
			lock_reg((fd), F_SETLKW, F_RDLCK, (offset), (whence), (len))
#define	write_lock(fd, offset, whence, len) \
			lock_reg((fd), F_SETLK, F_WRLCK, (offset), (whence), (len))
#define	writew_lock(fd, offset, whence, len) \
			lock_reg((fd), F_SETLKW, F_WRLCK, (offset), (whence), (len))
#define	un_lock(fd, offset, whence, len) \
			lock_reg((fd), F_SETLK, F_UNLCK, (offset), (whence), (len))

pid_t	lock_test(int, int, off_t, int, off_t);		/* {Prog locktest} */

#define	is_read_lockable(fd, offset, whence, len) \
			(lock_test((fd), F_RDLCK, (offset), (whence), (len)) == 0)
#define	is_write_lockable(fd, offset, whence, len) \
			(lock_test((fd), F_WRLCK, (offset), (whence), (len)) == 0)

void	err_dump(const char *, ...);		/* {App misc_source} */
void	err_msg(const char *, ...);
void	err_quit(const char *, ...);
void	err_exit(int, const char *, ...);
void	err_ret(const char *, ...);
void	err_sys(const char *, ...);

void	log_msg(const char *, ...);			/* {App misc_source} */
void	log_open(const char *, int, int);
void	log_quit(const char *, ...);
void	log_ret(const char *, ...);
void	log_sys(const char *, ...);

void	TELL_WAIT(void);		/* parent/child from {Sec race_conditions} */
void	TELL_PARENT(pid_t);
void	TELL_CHILD(pid_t);
void	WAIT_PARENT(void);
void	WAIT_CHILD(void);

#endif	/* _APUE_H */
$

0
Reply Uno 8/31/2010 6:34:38 AM

Gib Bogle wrote:
> Hi Richard, a couple of minor mods and this is working with 
> MinGW/gcc/gfortran.  No need for __stdcall, or uppercase, but 
> underscores need to be appended to C function names.
> Thanks a lot.
> Gib


Post it, bogart!
-- 
Uno
0
Reply Uno 8/31/2010 6:37:09 AM

I'll post the code in three pieces.
Here is tcpc.c

/* $Id: tcpc.c,v 1.1.1.1 2003/03/06 19:38:16 maine Exp $ */
/* $Name:  $ */

/* tcpc.c
  * tcp communication routines for getData.
  *
  * The read/write/close here are used in both clients and servers.
  * These routines must not directly or indirectly reference the
  * fortran write_error_msg routine because some versions of it
  * may call these routines.
  *
  * The routines for opening a tcp connection are different for
  * clients and servers.  Furthermore, the client one may
  * call write_error_msg.  Thus those routines are in separate files.
  *
  * This file has wrappers for the system routines that are
  * not directly or easily callable from Fortran.
  * Specific to system Fortran and C calling conventions.
  *
  * Version for MS Windows MS C and CVF.
  * Differences from nag version are:
  *   Different system include files.
  *   Different procedure name mangling convention in the defines
  *   Specify __stdcall in procedure headers.
  *   Use closesocket instead of close.
  *   Used SOCKET_ERROR to test for errors per MS docs,
  *     though the bsd-style test did appear to work.
  *
  * 11 Oct 91, Richard Maine: Version 1.0
  * 17 Jul 01, Richard Maine: MS Windows port.
  */

#include <winsock.h>

/* Defines to make routines fortran-callable */
#define tcp_close tcp_close_
#define tcp_read tcp_read_
#define tcp_write tcp_write_

void tcp_close(sock)
   int *sock;
{
   shutdown(*sock,2); /* clears any pending i/o. */
   closesocket(*sock);
}

/* Write to a tcp socket. */
void tcp_write(sock, buf, buflen, error)
   int *sock, *buflen, *error;
   char *buf;
{
   int i;

   i = send(*sock,buf,*buflen,0);
   *error = (i == SOCKET_ERROR);
}

/* Read from a tcp socket. */
void tcp_read(sock, buf, buflen, error)
   int *sock, *buflen, *error;
   char *buf;
{
   int nleft, nread;
   char *bufptr;

   bufptr = buf;
   nleft = *buflen;
   *error = 1;

//while (nleft > 0)
//    {
       nread = recv(*sock, bufptr, nleft, 0);
       if (nread == SOCKET_ERROR) return;
//     nleft -= nread;
//     bufptr += nread;
//    }

   *error = 0;
}
0
Reply Gib 8/31/2010 10:13:42 AM

client.c


/* Connect to a specified host and port.
  * Return a socket number in sock. */

void tcp_connect(sock, host_name, host_name_len, port, error)
   int *sock, *port, *error;
   char *host_name;
   int host_name_len;
{
   char cstring[129];
   int i;
   struct hostent *host_ent;
   struct sockaddr_in host;
   int keepalive;
   char *from, *to;
   WORD wver;
   WSADATA wsaData;

   *error = 1;

   /* Start up Windows sockets */
   if (started == 0) {
     started = 1;
     wver = MAKEWORD(2,0);
     i = WSAStartup(wver, &wsaData);
     printf("did WSAStartup\n");
   }

   /* Make host_name into a c string */
   for (i=0; (i<host_name_len) && (i<127) && (host_name[i] != ' '); i++)
     cstring[i] = host_name[i];
   cstring[i] = '\0';

   /* Find the host IP address */
   host.sin_family = AF_INET;
   host_ent = gethostbyname(cstring);
   if (host_ent==0) {printerrormsg("Can't find host address."); return;}
   /* Avoid bcopy/memcpy dependence. */
   from = (char *) host_ent->h_addr;
   to = (char *) &host.sin_addr;
   for (i=0; i<host_ent->h_length; i++) *to++ = *from++;

   /* Set the port */
   host.sin_port = htons((unsigned short int) *port);

   /* Create a socket */
   *sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
   if (*sock==INVALID_SOCKET) {printerrormsg("Can't create socket.");
     return;
   }

   /* Attempt connection */
   if (connect(*sock, (struct sockaddr *) &host, sizeof(host)) == SOCKET_ERROR)
     {printerrormsg("Connect failed."); closesocket(*sock); return;}

   /* Enable keepalive packets to check socket connection. */
   keepalive = 1;
   setsockopt(*sock, SOL_SOCKET, SO_KEEPALIVE, (char *) &keepalive, 4);

   *error = 0;
}
0
Reply Gib 8/31/2010 10:15:03 AM

This test program was designed to communicate with a test TCP server program 
(Python).  It tests sending and receiving messages.  At least you can see how 
the various C functions are called.

The C code is compiled with gcc:
gcc -c tcpc.c
gcc -c client.c
then built with the Fortran code, linking libws2_32.a:
gfortran fortest.f90 tcpc.o client.o -lws2_32

fortest.f90

! To test Richard Maine's TCP C code

subroutine write_error_sub(msg)
character*(*) :: msg
write(*,*) msg
end subroutine

program main
implicit none
integer :: sock, host_name_len, msglen, ndata, error
integer :: port = 5000
character*(128) :: host_name = 'localhost'
character*(128) :: msg
character*(128) :: data
character :: ans
!external :: tcp_connect

host_name_len = len_trim(host_name)
write(*,*) 'call tcp_connect'
call tcp_connect(sock, host_name, host_name_len, port, error)
write(*,*) 'error: ',error
if (error == 0) then
     write(*,*) 'Connection succeeded'
     msg = "Hello from fortest"
     msglen = len_trim(msg)
     call tcp_write(sock,msg,msglen,error)
     write(*,*) "sent msg: error: ",error
     do
         ndata = 128
         data = ' '
         call tcp_read(sock,data,ndata,error)
         if (error /= 0) then
             write(*,*) 'tcp_read error: ',error
             exit
         endif
         if ( data(1:2) == 'q ' .or. data(1:2) == 'Q ') then
             write(*,*) 'got Q'
             exit
         else
             write(*,*) "RECEIVED: " , trim(data)
             write(*,*) "Input text to send ( q or Q to Quit):"
             read(*,'(a)') msg
             msglen = len_trim(msg)
             call tcp_write(sock,msg,msglen,error)
             if (msg(1:2) == 'Q ' .or. msg(1:2) == 'q ') then
                 exit
             endif
         endif
     enddo
     call tcp_close(sock)
endif
end program
0
Reply Gib 8/31/2010 10:25:07 AM

On 31 aug, 12:25, Gib Bogle <g.bo...@auckland.no.spam.ac.nz> wrote:
> This test program was designed to communicate with a test TCP server prog=
ram
> (Python). =A0It tests sending and receiving messages. =A0At least you can=
 see how
> the various C functions are called.
>
> The C code is compiled with gcc:
> gcc -c tcpc.c
> gcc -c client.c
> then built with the Fortran code, linking libws2_32.a:
> gfortran fortest.f90 tcpc.o client.o -lws2_32
>
> fortest.f90
>
> ! To test Richard Maine's TCP C code
>
> subroutine write_error_sub(msg)
> character*(*) :: msg
> write(*,*) msg
> end subroutine
>
> program main
> implicit none
> integer :: sock, host_name_len, msglen, ndata, error
> integer :: port =3D 5000
> character*(128) :: host_name =3D 'localhost'
> character*(128) :: msg
> character*(128) :: data
> character :: ans
> !external :: tcp_connect
>
> host_name_len =3D len_trim(host_name)
> write(*,*) 'call tcp_connect'
> call tcp_connect(sock, host_name, host_name_len, port, error)
> write(*,*) 'error: ',error
> if (error =3D=3D 0) then
> =A0 =A0 =A0write(*,*) 'Connection succeeded'
> =A0 =A0 =A0msg =3D "Hello from fortest"
> =A0 =A0 =A0msglen =3D len_trim(msg)
> =A0 =A0 =A0call tcp_write(sock,msg,msglen,error)
> =A0 =A0 =A0write(*,*) "sent msg: error: ",error
> =A0 =A0 =A0do
> =A0 =A0 =A0 =A0 =A0ndata =3D 128
> =A0 =A0 =A0 =A0 =A0data =3D ' '
> =A0 =A0 =A0 =A0 =A0call tcp_read(sock,data,ndata,error)
> =A0 =A0 =A0 =A0 =A0if (error /=3D 0) then
> =A0 =A0 =A0 =A0 =A0 =A0 =A0write(*,*) 'tcp_read error: ',error
> =A0 =A0 =A0 =A0 =A0 =A0 =A0exit
> =A0 =A0 =A0 =A0 =A0endif
> =A0 =A0 =A0 =A0 =A0if ( data(1:2) =3D=3D 'q ' .or. data(1:2) =3D=3D 'Q ')=
 then
> =A0 =A0 =A0 =A0 =A0 =A0 =A0write(*,*) 'got Q'
> =A0 =A0 =A0 =A0 =A0 =A0 =A0exit
> =A0 =A0 =A0 =A0 =A0else
> =A0 =A0 =A0 =A0 =A0 =A0 =A0write(*,*) "RECEIVED: " , trim(data)
> =A0 =A0 =A0 =A0 =A0 =A0 =A0write(*,*) "Input text to send ( q or Q to Qui=
t):"
> =A0 =A0 =A0 =A0 =A0 =A0 =A0read(*,'(a)') msg
> =A0 =A0 =A0 =A0 =A0 =A0 =A0msglen =3D len_trim(msg)
> =A0 =A0 =A0 =A0 =A0 =A0 =A0call tcp_write(sock,msg,msglen,error)
> =A0 =A0 =A0 =A0 =A0 =A0 =A0if (msg(1:2) =3D=3D 'Q ' .or. msg(1:2) =3D=3D =
'q ') then
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0exit
> =A0 =A0 =A0 =A0 =A0 =A0 =A0endif
> =A0 =A0 =A0 =A0 =A0endif
> =A0 =A0 =A0enddo
> =A0 =A0 =A0call tcp_close(sock)
> endif
> end program

Interesting - would it be alright with you, Gib and Richard, if I put
this
(with due credits) in my Flibs project? (I will try and make it a bit
more
general wrt Fortran/C interfacing)

Regards,

Arjen
0
Reply arjen.markus895 (633) 8/31/2010 12:07:09 PM

Arjen Markus <arjen.markus895@gmail.com> wrote:

> Interesting - would it be alright with you, Gib and Richard, if I put
> this
> (with due credits) in my Flibs project? (I will try and make it a bit
> more
> general wrt Fortran/C interfacing)

I have no objection. You might find that you want to fiddle it a little
for general use, as there are some aspects I simplified, but that's up
to you. I see that Gib did a litle of that kind of thing, which is fine.
Notably, my apps had higher-level protocol that established exactly how
much data to expect from a read, which is why I had the loop reading
fragments until it got that much.

Note that the WSAStartup thing is purely Windows. That's a piece I would
never have guessed just by fiddling.

-- 
Richard Maine                    | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle           |  -- Mark Twain
0
Reply nospam 8/31/2010 4:18:08 PM

Arjen Markus wrote:

> Interesting - would it be alright with you, Gib and Richard, if I put
> this
> (with due credits) in my Flibs project? (I will try and make it a bit
> more
> general wrt Fortran/C interfacing)
> 
> Regards,
> 
> Arjen

That's perfectly OK with me.  Maybe next time someone who searches, like me, for 
gfortran and sockets on Windows, will find this.  As you point out, it needs to 
be made a bit more general.

If you felt inspired, you might extend it to handle the server case (just a bit 
more complicated).  Like Richard I need only the client at this stage.

Gib
0
Reply Gib 8/31/2010 10:28:53 PM

Here is some more C code that I found online, which shows how to handle both 
Windows and Unix environments, and also how to set up a TCP server.  I don't 
understand the significance of the Winsock.h/Winsock2.h distinction.

sockets.c (contributed by ReyBrujo)

#ifdef WIN32
    #include <Winsock2.h>
#else
     #include <sys/types.h>
     #include <sys/socket.h>

     #define closesocket close
#endif
#include <stdio.h>
#include <stdlib.h>

#define D_PORT      4344
#define D_HOST      "localhost"
#define D_QUEUE     32
#define D_SOCKETS   16
#define D_INFO      256

int main(int argc, char **argv) {
     struct timeval tv;
     struct sockaddr_in addr;
     struct hostent *host;
     unsigned int descriptor;
     int result;
     int index;
     int cycle = 0;
     int delay = 0;
     unsigned int sockets[D_SOCKETS];
     int sockets_index = 0;
     unsigned int maximum;
     char buffer[D_INFO];
     fd_set input;

     /*  read the delay if any  */
     if (argc > 1)
         delay = atol(argv[1]);
     else
         delay = 0;

#ifdef WIN32
     WSADATA wsaData;
     WSAStartup(MAKEWORD(2, 2), &wsaData);
#endif  /*  WIN32  */

     /*  create a socket  */
     descriptor = socket(PF_INET, SOCK_STREAM, 0);
     if (descriptor == -1) {
         perror("socket");
         return (1);
     }

     /*  get information about the host  */
     memset(&addr, 0, sizeof(addr));
     host = gethostbyname(D_HOST);
     if (host == NULL) {
         perror("gethostbyname");
         closesocket(descriptor);
#ifdef WIN32
         WSACleanup();
#endif
         return (1);
     }

     /*  bind the socket to an address and port  */
     memcpy(&addr.sin_addr, host->h_addr_list[0], sizeof(host->h_addr_list[0]));
     addr.sin_family = AF_INET;
     addr.sin_port   = htons(D_PORT);
     result = bind(descriptor, (struct sockaddr *)&addr, sizeof(addr));
     if (result == -1) {
         perror("bind");
         closesocket(descriptor);
#ifdef WIN32
         WSACleanup();
#endif
         return (1);
     }

     /*  listen for connections  */
     result = listen(descriptor, D_QUEUE);
     if (result == -1) {
         perror("listen");
         closesocket(descriptor);
#ifdef WIN32
         WSACleanup();
#endif
         return (1);
     }

     memset(sockets, 0, sizeof(sockets));
     maximum = descriptor;

     result = 0;
     while (result != -1) {
         FD_ZERO(&input);
         FD_SET(descriptor, &input);
         for (result = 0; result < sockets_index; result++)
             FD_SET(sockets[result], &input);

         tv.tv_sec  = delay;
         tv.tv_usec = 0;
         if (delay == -1)
             result = select(maximum + 1, &input, NULL, NULL, NULL);
         else
             result = select(maximum + 1, &input, NULL, NULL, &tv);
         switch (result) {
             /*  error in select  */
             case -1:
                 perror("select");
                break;

             /*  nothing to process  */
             case 0:
                 break;

             /*  a number of sockets are ready for reading  */
             default:
                 /*  check if the descriptor set is our listening one  */
                 if (FD_ISSET(descriptor , &input)) {
                     sockets[sockets_index] = accept(descriptor, NULL, NULL);
                     if (sockets[sockets_index] == -1) {
                         perror("accept");
                     }
                     else {
                         if (sockets[sockets_index] > maximum)
                             maximum = sockets[sockets_index];

                         sockets_index++;
                     }
                 }
                 /*  one of the sockets is sending data. Find it  */
                 else {
                     for (index = 0; index < sockets_index; index++) {
                         if (FD_ISSET(sockets[index], &input)) {
                             memset(buffer, 0, sizeof(buffer));

                             /*  read information from socket  */
                             result = recv(sockets[index], buffer, 
sizeof(buffer), 0);
                             if (result == -1)
                                 perror("recv");
                             else
                                 printf("Received %d bytes from descriptor %d: 
%s\n", result, sockets[index], buffer);
                         }
                     }
                 }
         }

         printf("%d\r", cycle++);
     }

     for (result = 0; result < sockets_index; result++) {
         closesocket(sockets[sockets_index]);
     }

     closesocket(descriptor);
#ifdef WIN32
     WSACleanup();
#endif

     return (0);
}
0
Reply Gib 8/31/2010 10:38:20 PM

Gib Bogle <g.bogle@auckland.no.spam.ac.nz> wrote:

> If you felt inspired, you might extend it to handle the server case (just
> a bit more complicated).  Like Richard I need only the client at this
> stage.

Should anyone care, here's the comparable stuff I had for my servers. I
did not port this to Windows, and it hasn't even been used on a wide
variety of Unix systems - just the few we were using for servers. It
started out on SunOS 4, ported to Solaris 2, and I think I recall
experimenting with this on Linux.

I wrote this stuff about 20 years ago. It is currently still in wide use
at NASA Dryden (and I don't see any sign of that changing soon).

/* $Id: serverc.c,v 1.2 2005/12/28 22:49:13 maine Exp $ */
/* $Name:  $ */

/* serverc.c
 * listen for a connection attempt to a getData server.
 *
 * The read/write/close routines are used in both clients and servers
 * and are in a separate file.
 *
 * This file has wrappers for the system routines that are
 * not directly or easily callable from Fortran.
 * Specific to system Fortran and C calling conventions.
 *
 * Version for SunOS 4.1.x with NAG f90 1.2.
 * Note, specifically that Sun Fortran puts character length
 * information at the end of the argument list instead of right
 * after the corresponding arguments.
 *
 * 28 Jun 93, Richard Maine: Version 1.5.
 * 19 Nov 96, Richard Maine: casts to avoid gcc warnings.
 * 16 Apr 98, Richard Maine: fix sol2 sigchld handling.
 * 2 Dec 98, Richard Maine: fix addr len in gethostbyaddr.
 * 21 Dec 05, Richard Maine: avoid sun-specific in_addr structure.
 */

#include <sys/types.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

/* Defines to make routines fortran-callable */
#define tcp_listen tcp_listen_

/* handler for SIGCHLD signal
 * Needed so that child processes can be decently buried when they die.
 * USG systems may need signal handler reestablished after use?
 * but we are not using this for SOL2. */

void child_handler(sig)
  int sig;
{
  wait3(0, WNOHANG, 0);
  return;
}

/* Listen for connection attempts on the specified port.
 * Fork a child for each connection.
 * Return connection information.
 * Normal return value for child is 0.
 * Positive return values are errors in parent.
 * Negative return values are errors in child. */

void tcp_listen(port ,sock, client_ip, client_port, client_name, 
     server_ip, connect_num, error, client_name_len)
  int *port, *sock, *client_port, *connect_num, *error;
  int client_ip[3], server_ip[3];
  char *client_name;
  int client_name_len;
{
  struct sockaddr_in server_addr, client_addr;
  int lsock; /* Socket for listening */
  int addr_size = sizeof(server_addr);
  int addr_len;
  int pid;
  int keepalive;
  struct hostent *host_ent;
  int i;
  unsigned char *ip_byte;

  /* Divorce ourselves from controlling terminal. */
  /*  See Stevens, Chapter 13. */
  
  if (fork()>0) exit(0);  /* Parent returns; child continues. */
  setsid();  /* Become session leader */

  /* Create a socket, bind it to specified port and listen. */

  *connect_num = 0;
  lsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  if (lsock<0) {*error=1; return;}
  server_addr.sin_family = AF_INET;
  server_addr.sin_addr.s_addr = INADDR_ANY;
  server_addr.sin_port = htons(*port);
  if (bind(lsock, (struct sockaddr *) &server_addr, addr_size) < 0)
    {*error=2; return;}
  if (listen(lsock,5) < 0) {*error=3; return;}

  /* Accept connections and fork server instances. */

#ifdef SOL2
  signal(SIGCHLD, SIG_IGN);
#else
  signal(SIGCHLD, child_handler);
#endif

  for (;;) {
    addr_len = addr_size;
    *sock = accept(lsock, (struct sockaddr *) &client_addr, &addr_len);

    /* For reasons unclear to me, we get a lot of accept failures. */
    /* perror says something about interrupted system call. */
    /* We just ignore them for now. */
    /* Can count them by moving the connect_num incrementation. */

    if (*sock<0) continue; /* Connect failed */
    *connect_num = *connect_num + 1;

    /* Child process.  Return connection data. */
    if (fork()==0) {
      close(lsock);
      ip_byte = (unsigned char *) &client_addr.sin_addr;
      client_ip[0] = *(ip_byte++);
      client_ip[1] = *(ip_byte++);
      client_ip[2] = *(ip_byte++);
      client_ip[3] = *(ip_byte++);
      *client_port = ntohs(client_addr.sin_port);
      host_ent = gethostbyaddr((char *) &client_addr.sin_addr.s_addr,
           sizeof(client_addr.sin_addr.s_addr), AF_INET);
      for (i=0; i<client_name_len; i++) client_name[i] = ' ';
      if (host_ent) {
        for (i=0; (i<client_name_len) && (host_ent->h_name[i]!=0); i++)
          client_name[i] = host_ent->h_name[i];
      }

      addr_len = addr_size;
      getsockname(*sock, (struct sockaddr *) &server_addr, &addr_len);
      ip_byte = (unsigned char *) &server_addr.sin_addr;
      server_ip[0] = *(ip_byte++);
      server_ip[1] = *(ip_byte++);
      server_ip[2] = *(ip_byte++);
      server_ip[3] = *(ip_byte++);

      signal(SIGCHLD, SIG_DFL);

      /* We want an error return from writes to closed sockets so
       * we can shut down cleanly and log the termination.
       * Without this, we quitely die.
       */
      signal (SIGPIPE, SIG_IGN);

      /* Enable keepalive packets to check socket connection. */
      keepalive = 1;
      setsockopt(*sock, SOL_SOCKET, SO_KEEPALIVE, (char *) &keepalive,
4);

      /* Allow SIGIO/SIGURG to signal this process. */
      /* Not currently needed.  Retain as comment. */
      /*   if (fcntl(*sock, F_SETOWN, getpid()) < 0) return(-1); */
      /*   if (fcntl(*sock, F_SETFL, FASYNC) < 0) return (-2);   */

      *error=0;
      return;
    }

    /* Parent process.  Loop back for further connections. */
    close(*sock);
  }

}

-- 
Richard Maine                    | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle           |  -- Mark Twain
0
Reply nospam 8/31/2010 11:05:31 PM

On 1 sep, 00:38, Gib Bogle <g.bo...@auckland.no.spam.ac.nz> wrote:
> Here is some more C code that I found online, which shows how to handle b=
oth
> Windows and Unix environments, and also how to set up a TCP server. =A0I =
don't
> understand the significance of the Winsock.h/Winsock2.h distinction.
>
> sockets.c (contributed by ReyBrujo)
>
> #ifdef WIN32
> =A0 =A0 #include <Winsock2.h>
> #else
> =A0 =A0 =A0#include <sys/types.h>
> =A0 =A0 =A0#include <sys/socket.h>
>
> =A0 =A0 =A0#define closesocket close
> #endif
> #include <stdio.h>
> #include <stdlib.h>
>
> #define D_PORT =A0 =A0 =A04344
> #define D_HOST =A0 =A0 =A0"localhost"
> #define D_QUEUE =A0 =A0 32
> #define D_SOCKETS =A0 16
> #define D_INFO =A0 =A0 =A0256
>
> int main(int argc, char **argv) {
> =A0 =A0 =A0struct timeval tv;
> =A0 =A0 =A0struct sockaddr_in addr;
> =A0 =A0 =A0struct hostent *host;
> =A0 =A0 =A0unsigned int descriptor;
> =A0 =A0 =A0int result;
> =A0 =A0 =A0int index;
> =A0 =A0 =A0int cycle =3D 0;
> =A0 =A0 =A0int delay =3D 0;
> =A0 =A0 =A0unsigned int sockets[D_SOCKETS];
> =A0 =A0 =A0int sockets_index =3D 0;
> =A0 =A0 =A0unsigned int maximum;
> =A0 =A0 =A0char buffer[D_INFO];
> =A0 =A0 =A0fd_set input;
>
> =A0 =A0 =A0/* =A0read the delay if any =A0*/
> =A0 =A0 =A0if (argc > 1)
> =A0 =A0 =A0 =A0 =A0delay =3D atol(argv[1]);
> =A0 =A0 =A0else
> =A0 =A0 =A0 =A0 =A0delay =3D 0;
>
> #ifdef WIN32
> =A0 =A0 =A0WSADATA wsaData;
> =A0 =A0 =A0WSAStartup(MAKEWORD(2, 2), &wsaData);
> #endif =A0/* =A0WIN32 =A0*/
>
> =A0 =A0 =A0/* =A0create a socket =A0*/
> =A0 =A0 =A0descriptor =3D socket(PF_INET, SOCK_STREAM, 0);
> =A0 =A0 =A0if (descriptor =3D=3D -1) {
> =A0 =A0 =A0 =A0 =A0perror("socket");
> =A0 =A0 =A0 =A0 =A0return (1);
> =A0 =A0 =A0}
>
> =A0 =A0 =A0/* =A0get information about the host =A0*/
> =A0 =A0 =A0memset(&addr, 0, sizeof(addr));
> =A0 =A0 =A0host =3D gethostbyname(D_HOST);
> =A0 =A0 =A0if (host =3D=3D NULL) {
> =A0 =A0 =A0 =A0 =A0perror("gethostbyname");
> =A0 =A0 =A0 =A0 =A0closesocket(descriptor);
> #ifdef WIN32
> =A0 =A0 =A0 =A0 =A0WSACleanup();
> #endif
> =A0 =A0 =A0 =A0 =A0return (1);
> =A0 =A0 =A0}
>
> =A0 =A0 =A0/* =A0bind the socket to an address and port =A0*/
> =A0 =A0 =A0memcpy(&addr.sin_addr, host->h_addr_list[0], sizeof(host->h_ad=
dr_list[0]));
> =A0 =A0 =A0addr.sin_family =3D AF_INET;
> =A0 =A0 =A0addr.sin_port =A0 =3D htons(D_PORT);
> =A0 =A0 =A0result =3D bind(descriptor, (struct sockaddr *)&addr, sizeof(a=
ddr));
> =A0 =A0 =A0if (result =3D=3D -1) {
> =A0 =A0 =A0 =A0 =A0perror("bind");
> =A0 =A0 =A0 =A0 =A0closesocket(descriptor);
> #ifdef WIN32
> =A0 =A0 =A0 =A0 =A0WSACleanup();
> #endif
> =A0 =A0 =A0 =A0 =A0return (1);
> =A0 =A0 =A0}
>
> =A0 =A0 =A0/* =A0listen for connections =A0*/
> =A0 =A0 =A0result =3D listen(descriptor, D_QUEUE);
> =A0 =A0 =A0if (result =3D=3D -1) {
> =A0 =A0 =A0 =A0 =A0perror("listen");
> =A0 =A0 =A0 =A0 =A0closesocket(descriptor);
> #ifdef WIN32
> =A0 =A0 =A0 =A0 =A0WSACleanup();
> #endif
> =A0 =A0 =A0 =A0 =A0return (1);
> =A0 =A0 =A0}
>
> =A0 =A0 =A0memset(sockets, 0, sizeof(sockets));
> =A0 =A0 =A0maximum =3D descriptor;
>
> =A0 =A0 =A0result =3D 0;
> =A0 =A0 =A0while (result !=3D -1) {
> =A0 =A0 =A0 =A0 =A0FD_ZERO(&input);
> =A0 =A0 =A0 =A0 =A0FD_SET(descriptor, &input);
> =A0 =A0 =A0 =A0 =A0for (result =3D 0; result < sockets_index; result++)
> =A0 =A0 =A0 =A0 =A0 =A0 =A0FD_SET(sockets[result], &input);
>
> =A0 =A0 =A0 =A0 =A0tv.tv_sec =A0=3D delay;
> =A0 =A0 =A0 =A0 =A0tv.tv_usec =3D 0;
> =A0 =A0 =A0 =A0 =A0if (delay =3D=3D -1)
> =A0 =A0 =A0 =A0 =A0 =A0 =A0result =3D select(maximum + 1, &input, NULL, N=
ULL, NULL);
> =A0 =A0 =A0 =A0 =A0else
> =A0 =A0 =A0 =A0 =A0 =A0 =A0result =3D select(maximum + 1, &input, NULL, N=
ULL, &tv);
> =A0 =A0 =A0 =A0 =A0switch (result) {
> =A0 =A0 =A0 =A0 =A0 =A0 =A0/* =A0error in select =A0*/
> =A0 =A0 =A0 =A0 =A0 =A0 =A0case -1:
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0perror("select");
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
>
> =A0 =A0 =A0 =A0 =A0 =A0 =A0/* =A0nothing to process =A0*/
> =A0 =A0 =A0 =A0 =A0 =A0 =A0case 0:
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break;
>
> =A0 =A0 =A0 =A0 =A0 =A0 =A0/* =A0a number of sockets are ready for readin=
g =A0*/
> =A0 =A0 =A0 =A0 =A0 =A0 =A0default:
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* =A0check if the descriptor set is o=
ur listening one =A0*/
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (FD_ISSET(descriptor , &input)) {
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0sockets[sockets_index] =3D acc=
ept(descriptor, NULL, NULL);
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (sockets[sockets_index] =3D=
=3D -1) {
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0perror("accept");
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0}
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0else {
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (sockets[sockets_in=
dex] > maximum)
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0maximum =3D so=
ckets[sockets_index];
>
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0sockets_index++;
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0}
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0}
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* =A0one of the sockets is sending da=
ta. Find it =A0*/
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0else {
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0for (index =3D 0; index < sock=
ets_index; index++) {
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (FD_ISSET(sockets[i=
ndex], &input)) {
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0memset(buffer,=
 0, sizeof(buffer));
>
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* =A0read inf=
ormation from socket =A0*/
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0result =3D rec=
v(sockets[index], buffer,
> sizeof(buffer), 0);
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (result =3D=
=3D -1)
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0perror=
("recv");
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0else
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0printf=
("Received %d bytes from descriptor %d:
> %s\n", result, sockets[index], buffer);
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0}
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0}
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0}
> =A0 =A0 =A0 =A0 =A0}
>
> =A0 =A0 =A0 =A0 =A0printf("%d\r", cycle++);
> =A0 =A0 =A0}
>
> =A0 =A0 =A0for (result =3D 0; result < sockets_index; result++) {
> =A0 =A0 =A0 =A0 =A0closesocket(sockets[sockets_index]);
> =A0 =A0 =A0}
>
> =A0 =A0 =A0closesocket(descriptor);
> #ifdef WIN32
> =A0 =A0 =A0WSACleanup();
> #endif
>
> =A0 =A0 =A0return (0);
>
>
>
> }- Tekst uit oorspronkelijk bericht niet weergeven -
>
> - Tekst uit oorspronkelijk bericht weergeven -

Wonderful, this looks very promising. The tough part is getting
started
with such a programming task, but with these implementations it ought
to be lighter work. (Will keep you up-to-date as to the progress I
make
with it - which may be slow ;))

Regards,

Arjen
0
Reply arjen.markus895 (633) 9/1/2010 6:57:53 AM

On 8/31/2010 3:25 AM, Gib Bogle wrote:
> This test program was designed to communicate with a test TCP server
> program (Python). It tests sending and receiving messages. At least you
> can see how the various C functions are called.
>
> The C code is compiled with gcc:
> gcc -c tcpc.c
> gcc -c client.c
> then built with the Fortran code, linking libws2_32.a:
> gfortran fortest.f90 tcpc.o client.o -lws2_32
>

Where did you find that library?  This is brand spanking new from 
equation.com, which I thought were mingw-based:

Dir for this script: C:\eq\source\

C:\eq\source>dir
  Volume in drive C has no label.
  Volume Serial Number is 942A-AD55

  Directory of C:\eq\source

09/01/2010  03:35 PM    <DIR>          .
09/01/2010  03:35 PM    <DIR>          ..
05/14/2010  02:19 PM               218 run1.bat
                1 File(s)            218 bytes
                2 Dir(s)  32,663,818,240 bytes free

C:\eq\source>gfortran anything
gfortran: anything: No such file or directory

C:\eq\source>cd ..

C:\eq>dir
  Volume in drive C has no label.
  Volume Serial Number is 942A-AD55

  Directory of C:\eq

09/01/2010  03:32 PM    <DIR>          .
09/01/2010  03:32 PM    <DIR>          ..
09/01/2010  03:35 PM               823 32 bit.lnk
09/01/2010  03:26 PM    <DIR>          bin
08/04/2004  07:00 AM           388,608 cmd.exe
09/01/2010  03:26 PM    <DIR>          i686-pc-mingw32
09/01/2010  03:26 PM    <DIR>          include
09/01/2010  03:26 PM    <DIR>          lib
09/01/2010  03:26 PM    <DIR>          libexec
09/01/2010  03:26 PM    <DIR>          manual
09/01/2010  03:26 PM    <DIR>          share
09/01/2010  03:35 PM    <DIR>          source
                2 File(s)        389,431 bytes
               10 Dir(s)  32,663,818,240 bytes free

C:\eq>cd include

C:\eq\include>dir
  Volume in drive C has no label.
  Volume Serial Number is 942A-AD55

  Directory of C:\eq\include

09/01/2010  03:26 PM    <DIR>          .
09/01/2010  03:26 PM    <DIR>          ..
09/01/2010  03:26 PM            13,917 ansidecl.h
09/01/2010  03:26 PM           196,800 bfd.h
09/01/2010  03:26 PM            29,513 bfdlink.h
09/01/2010  03:26 PM    <DIR>          c++
09/01/2010  03:26 PM            16,736 dis-asm.h
09/01/2010  03:26 PM             2,198 symcat.h
                5 File(s)        259,164 bytes
                3 Dir(s)  32,663,818,240 bytes free

C:\eq\include>cd ..

C:\eq>cd lib

C:\eq\lib>dir
  Volume in drive C has no label.
  Volume Serial Number is 942A-AD55

  Directory of C:\eq\lib

09/01/2010  03:26 PM    <DIR>          .
09/01/2010  03:26 PM    <DIR>          ..
09/01/2010  03:26 PM    <DIR>          gcc
09/01/2010  03:26 PM           823,008 libbfd.a
09/01/2010  03:26 PM               933 libbfd.la
09/01/2010  03:26 PM         5,338,594 libgfortran.a
09/01/2010  03:26 PM             1,103 libgfortran.la
09/01/2010  03:26 PM           292,254 libgomp.a
09/01/2010  03:26 PM             1,091 libgomp.la
09/01/2010  03:26 PM               154 libgomp.spec
09/01/2010  03:26 PM           774,684 libiberty.a
09/01/2010  03:26 PM           609,982 libopcodes.a
09/01/2010  03:26 PM               945 libopcodes.la
09/01/2010  03:26 PM            36,262 libssp.a
09/01/2010  03:26 PM             1,088 libssp.la
09/01/2010  03:26 PM             2,020 libssp_nonshared.a
09/01/2010  03:26 PM             1,118 libssp_nonshared.la
09/01/2010  03:26 PM         8,672,836 libstdc++.a
09/01/2010  03:26 PM             2,400 libstdc++.a-gdb.py
09/01/2010  03:26 PM               943 libstdc++.la
09/01/2010  03:26 PM           647,358 libsupc++.a
09/01/2010  03:26 PM               942 libsupc++.la
               19 File(s)     17,207,715 bytes
                3 Dir(s)  32,663,818,240 bytes free

C:\eq\lib>cd gcc

C:\eq\lib\gcc>dir
  Volume in drive C has no label.
  Volume Serial Number is 942A-AD55

  Directory of C:\eq\lib\gcc

09/01/2010  03:26 PM    <DIR>          .
09/01/2010  03:26 PM    <DIR>          ..
09/01/2010  03:26 PM    <DIR>          i686-pc-mingw32
                0 File(s)              0 bytes
                3 Dir(s)  32,663,818,240 bytes free

C:\eq\lib\gcc>cd i686-pc-mingw32

C:\eq\lib\gcc\i686-pc-mingw32>dir
  Volume in drive C has no label.
  Volume Serial Number is 942A-AD55

  Directory of C:\eq\lib\gcc\i686-pc-mingw32

09/01/2010  03:26 PM    <DIR>          .
09/01/2010  03:26 PM    <DIR>          ..
09/01/2010  03:26 PM    <DIR>          4.5.1
                0 File(s)              0 bytes
                3 Dir(s)  32,663,818,240 bytes free

C:\eq\lib\gcc\i686-pc-mingw32>cd 4.5.1

C:\eq\lib\gcc\i686-pc-mingw32\4.5.1>dir
  Volume in drive C has no label.
  Volume Serial Number is 942A-AD55

  Directory of C:\eq\lib\gcc\i686-pc-mingw32\4.5.1

09/01/2010  03:26 PM    <DIR>          .
09/01/2010  03:26 PM    <DIR>          ..
09/01/2010  03:26 PM               966 crtbegin.o
09/01/2010  03:26 PM               734 crtend.o
09/01/2010  03:26 PM             3,503 crtfastmath.o
09/01/2010  03:26 PM    <DIR>          finclude
09/01/2010  03:26 PM    <DIR>          include
09/01/2010  03:26 PM    <DIR>          include-fixed
09/01/2010  03:26 PM    <DIR>          install-tools
09/01/2010  03:26 PM           550,218 libgcc.a
09/01/2010  03:26 PM            87,434 libgcov.a
09/01/2010  03:26 PM             4,350 libgfortranbegin.a
09/01/2010  03:26 PM             1,144 libgfortranbegin.la
                7 File(s)        648,349 bytes
                6 Dir(s)  32,663,818,240 bytes free

C:\eq\lib\gcc\i686-pc-mingw32\4.5.1>
-- 
Uno
0
Reply Uno 9/1/2010 10:44:00 PM

Uno wrote:
> On 8/31/2010 3:25 AM, Gib Bogle wrote:
>> This test program was designed to communicate with a test TCP server
>> program (Python). It tests sending and receiving messages. At least you
>> can see how the various C functions are called.
>>
>> The C code is compiled with gcc:
>> gcc -c tcpc.c
>> gcc -c client.c
>> then built with the Fortran code, linking libws2_32.a:
>> gfortran fortest.f90 tcpc.o client.o -lws2_32
>>
> 
> Where did you find that library?  This is brand spanking new from 
> equation.com, which I thought were mingw-based:

Did you install MinGW?
I've installed both mingw-4.4 and mingw64-4.5.  In the 32-bit installation 
libws2_32.a is in mingw-4.4\lib, while in the 64=bit version it's in 
mingw64-4.5\x86_64-w64-mingw32 (unless I've made a typo).  My gfortran is 
installed as part of mingw64-4.5.

BTW I'm using Code:Blocks as the IDE, and I guess it's smart enough to find the 
various libraries.  I've just started playing with CB, and I'm quite impressed. 
  There is a bit of a funny trick to getting it to use gfortran, since in 
principle it knows about only C compilers.  You have to tell it to make a copy 
of the GCC C compiler, then rename and customise that copy so it uses gfortran. 
  It isn't as powerful as MSVS, but it's doing the job for me so far.  The great 
thing, of course, is that it's free and multi-platform.
0
Reply Gib 9/2/2010 12:31:11 AM

On 2 sep, 02:31, Gib Bogle <g.bo...@auckland.no.spam.ac.nz> wrote:
> Uno wrote:
> > On 8/31/2010 3:25 AM, Gib Bogle wrote:
> >> This test program was designed to communicate with a test TCP server
> >> program (Python). It tests sending and receiving messages. At least yo=
u
> >> can see how the various C functions are called.
>
> >> The C code is compiled with gcc:
> >> gcc -c tcpc.c
> >> gcc -c client.c
> >> then built with the Fortran code, linking libws2_32.a:
> >> gfortran fortest.f90 tcpc.o client.o -lws2_32
>
> > Where did you find that library? =A0This is brand spanking new from
> > equation.com, which I thought were mingw-based:
>
> Did you install MinGW?
> I've installed both mingw-4.4 and mingw64-4.5. =A0In the 32-bit installat=
ion
> libws2_32.a is in mingw-4.4\lib, while in the 64=3Dbit version it's in
> mingw64-4.5\x86_64-w64-mingw32 (unless I've made a typo). =A0My gfortran =
is
> installed as part of mingw64-4.5.
>
> BTW I'm using Code:Blocks as the IDE, and I guess it's smart enough to fi=
nd the
> various libraries. =A0I've just started playing with CB, and I'm quite im=
pressed.
> =A0 There is a bit of a funny trick to getting it to use gfortran, since =
in
> principle it knows about only C compilers. =A0You have to tell it to make=
 a copy
> of the GCC C compiler, then rename and customise that copy so it uses gfo=
rtran.
> =A0 It isn't as powerful as MSVS, but it's doing the job for me so far. =
=A0The great
> thing, of course, is that it's free and multi-platform.

I have installed the equation.com version of gfortran and it comes
with the
libws_32.a library, alright. But perhaps not the very latest
version ...

Regards,

Arjen

0
Reply arjen.markus895 (633) 9/2/2010 6:58:25 AM

On 31 aug, 12:25, Gib Bogle <g.bo...@auckland.no.spam.ac.nz> wrote:
> This test program was designed to communicate with a test TCP server prog=
ram
> (Python). =A0It tests sending and receiving messages. =A0At least you can=
 see how
> the various C functions are called.
>
> The C code is compiled with gcc:
> gcc -c tcpc.c
> gcc -c client.c
> then built with the Fortran code, linking libws2_32.a:
> gfortran fortest.f90 tcpc.o client.o -lws2_32
>
> fortest.f90
>
> ! To test Richard Maine's TCP C code
>
> subroutine write_error_sub(msg)
> character*(*) :: msg
> write(*,*) msg
> end subroutine
>
> program main
> implicit none
> integer :: sock, host_name_len, msglen, ndata, error
> integer :: port =3D 5000
> character*(128) :: host_name =3D 'localhost'
> character*(128) :: msg
> character*(128) :: data
> character :: ans
> !external :: tcp_connect
>
> host_name_len =3D len_trim(host_name)
> write(*,*) 'call tcp_connect'
> call tcp_connect(sock, host_name, host_name_len, port, error)
> write(*,*) 'error: ',error
> if (error =3D=3D 0) then
> =A0 =A0 =A0write(*,*) 'Connection succeeded'
> =A0 =A0 =A0msg =3D "Hello from fortest"
> =A0 =A0 =A0msglen =3D len_trim(msg)
> =A0 =A0 =A0call tcp_write(sock,msg,msglen,error)
> =A0 =A0 =A0write(*,*) "sent msg: error: ",error
> =A0 =A0 =A0do
> =A0 =A0 =A0 =A0 =A0ndata =3D 128
> =A0 =A0 =A0 =A0 =A0data =3D ' '
> =A0 =A0 =A0 =A0 =A0call tcp_read(sock,data,ndata,error)
> =A0 =A0 =A0 =A0 =A0if (error /=3D 0) then
> =A0 =A0 =A0 =A0 =A0 =A0 =A0write(*,*) 'tcp_read error: ',error
> =A0 =A0 =A0 =A0 =A0 =A0 =A0exit
> =A0 =A0 =A0 =A0 =A0endif
> =A0 =A0 =A0 =A0 =A0if ( data(1:2) =3D=3D 'q ' .or. data(1:2) =3D=3D 'Q ')=
 then
> =A0 =A0 =A0 =A0 =A0 =A0 =A0write(*,*) 'got Q'
> =A0 =A0 =A0 =A0 =A0 =A0 =A0exit
> =A0 =A0 =A0 =A0 =A0else
> =A0 =A0 =A0 =A0 =A0 =A0 =A0write(*,*) "RECEIVED: " , trim(data)
> =A0 =A0 =A0 =A0 =A0 =A0 =A0write(*,*) "Input text to send ( q or Q to Qui=
t):"
> =A0 =A0 =A0 =A0 =A0 =A0 =A0read(*,'(a)') msg
> =A0 =A0 =A0 =A0 =A0 =A0 =A0msglen =3D len_trim(msg)
> =A0 =A0 =A0 =A0 =A0 =A0 =A0call tcp_write(sock,msg,msglen,error)
> =A0 =A0 =A0 =A0 =A0 =A0 =A0if (msg(1:2) =3D=3D 'Q ' .or. msg(1:2) =3D=3D =
'q ') then
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0exit
> =A0 =A0 =A0 =A0 =A0 =A0 =A0endif
> =A0 =A0 =A0 =A0 =A0endif
> =A0 =A0 =A0enddo
> =A0 =A0 =A0call tcp_close(sock)
> endif
> end program

There is an interfacing problem here:

In calls like:

    call tcp_write(sock,msg,msglen,error)

the argument msglen is not needed. The C source does define it, but
that
is because most Fortran implementations pass the length of a string as
a hidden argument. This argument is visible on the C side, but it is
an integer _value_, not as with all other arguments a pointer.

The above call should be:

   call tcp_write(sock,msg,error)

(Unfortunately, the position of the hidden argument depends on the
Fortran compiler you use, and possibly on flags you pass. That is
one of the things I want to generalise in this code ;). F2003 uses
a different solution: by regarding character strings as arrays of
characters (len=3D1))

Regards,

Arjen
0
Reply arjen.markus895 (633) 9/2/2010 7:03:15 AM

Arjen Markus <arjen.markus895@gmail.com> wrote:

>     call tcp_write(sock,msg,msglen,error)
> 
> the argument msglen is not needed....
  [explains the usual issue with Fortran/C character passing]

> The above call should be:
> 
>    call tcp_write(sock,msg,error)

Except that I think you'll find that won't work because my tcp_write
expects msglen to be passed by address instead of by value as will
probably happen with most implementations (as you correctly describe).
This is intentional. The documentation I provided in the post was
admitedly... um... minimal. But the idea was that msg should *NOT* be a
character string on the Fortran side. After all, character is (in my
view, expressed here before) a poor choice for an arbitrary bit bucket.
I tend to use arrays of integers (generally 1-byte ones) for buffers
like this. I think you'll find that if msg is an array of integers, that
the first form shown above is appropriate.

(Yes, I know it is a pointer to char on the C side, but C is ... funny
that way in that char is numeric.)

Gib's test happened to use character data, but that's not a general
property of tcp data buffers.

-- 
Richard Maine                    | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle           |  -- Mark Twain
0
Reply nospam 9/2/2010 7:59:09 AM

Arjen Markus wrote:
  > There is an interfacing problem here:
> 
> In calls like:
> 
>     call tcp_write(sock,msg,msglen,error)
> 
> the argument msglen is not needed. The C source does define it, but
> that
> is because most Fortran implementations pass the length of a string as
> a hidden argument. This argument is visible on the C side, but it is
> an integer _value_, not as with all other arguments a pointer.
> 
> The above call should be:
> 
>    call tcp_write(sock,msg,error)
> 
> (Unfortunately, the position of the hidden argument depends on the
> Fortran compiler you use, and possibly on flags you pass. That is
> one of the things I want to generalise in this code ;). F2003 uses
> a different solution: by regarding character strings as arrays of
> characters (len=1))

Hi Arjen,

Obviously I wasn't concentrating when I worked on this, because I am aware of 
this string-passing issue (there was something nagging at the back of my mind 
but I ignored it).  Now I'm wondering why it seemed to pass the brief test I 
gave it.  A puzzle that I'll have to defer until tomorrow - it's getting late here.

Gib
0
Reply Gib 9/2/2010 9:01:16 AM

On 2 sep, 09:59, nos...@see.signature (Richard Maine) wrote:
> Arjen Markus <arjen.markus...@gmail.com> wrote:
> > =A0 =A0 call tcp_write(sock,msg,msglen,error)
>
> > the argument msglen is not needed....
>
> =A0 [explains the usual issue with Fortran/C character passing]
>
> > The above call should be:
>
> > =A0 =A0call tcp_write(sock,msg,error)
>
> Except that I think you'll find that won't work because my tcp_write
> expects msglen to be passed by address instead of by value as will
> probably happen with most implementations (as you correctly describe).
> This is intentional. The documentation I provided in the post was
> admitedly... um... minimal. But the idea was that msg should *NOT* be a
> character string on the Fortran side. After all, character is (in my
> view, expressed here before) a poor choice for an arbitrary bit bucket.
> I tend to use arrays of integers (generally 1-byte ones) for buffers
> like this. I think you'll find that if msg is an array of integers, that
> the first form shown above is appropriate.
>
> (Yes, I know it is a pointer to char on the C side, but C is ... funny
> that way in that char is numeric.)
>
> Gib's test happened to use character data, but that's not a general
> property of tcp data buffers.
>
> --
> Richard Maine =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0| Good judgment come=
s from experience;
> email: last name at domain . net | experience comes from bad judgment.
> domain: summertriangle =A0 =A0 =A0 =A0 =A0 | =A0-- Mark Twain

Ah, right - oversight at my end. I had seen this for tcl_connect and
transposed the pattern to tcl_write without actually looking.

tcl_connect does expect a character string (and host_name_len is a
plain int)

Now I understand why :).

And yes, C is funny (for funny values of funny) wrt characters - in
many
implementations they are signed and there is a special connection
between
chars and ints that comes into play from time to time.

Regards,

Arjen
0
Reply arjen.markus895 (633) 9/2/2010 11:51:20 AM

On 2 sep, 11:01, Gib Bogle <g.bo...@auckland.no.spam.ac.nz> wrote:
> Arjen Markus wrote:
>
> =A0 > There is an interfacing problem here:
>
>
>
>
>
>
>
> > In calls like:
>
> > =A0 =A0 call tcp_write(sock,msg,msglen,error)
>
> > the argument msglen is not needed. The C source does define it, but
> > that
> > is because most Fortran implementations pass the length of a string as
> > a hidden argument. This argument is visible on the C side, but it is
> > an integer _value_, not as with all other arguments a pointer.
>
> > The above call should be:
>
> > =A0 =A0call tcp_write(sock,msg,error)
>
> > (Unfortunately, the position of the hidden argument depends on the
> > Fortran compiler you use, and possibly on flags you pass. That is
> > one of the things I want to generalise in this code ;). F2003 uses
> > a different solution: by regarding character strings as arrays of
> > characters (len=3D1))
>
> Hi Arjen,
>
> Obviously I wasn't concentrating when I worked on this, because I am awar=
e of
> this string-passing issue (there was something nagging at the back of my =
mind
> but I ignored it). =A0Now I'm wondering why it seemed to pass the brief t=
est I
> gave it. =A0A puzzle that I'll have to defer until tomorrow - it's gettin=
g late here.
>
> Gib- Tekst uit oorspronkelijk bericht niet weergeven -
>
> - Tekst uit oorspronkelijk bericht weergeven -

It is only the tcp_connect() routine that is important here -
tcp_write()
works as you thought.

Regards,

Arjen
0
Reply arjen.markus895 (633) 9/2/2010 11:52:11 AM

Arjen Markus wrote:

<snipped because my newsreader puts a limit on quoted characters>

>> Obviously I wasn't concentrating when I worked on this, because I am aware of
>> this string-passing issue (there was something nagging at the back of my mind
>> but I ignored it).  Now I'm wondering why it seemed to pass the brief test I
>> gave it.  A puzzle that I'll have to defer until tomorrow - it's getting late here.
>>
>> Gib- Tekst uit oorspronkelijk bericht niet weergeven -
>>
>> - Tekst uit oorspronkelijk bericht weergeven -
> 
> It is only the tcp_connect() routine that is important here -
> tcp_write()
> works as you thought.

Interesting.  In fact tcp_connect() was not working correctly as I had it, 
although it appeared to.  host_name_len passed as an int was giving a garbage 
value (a big positive number), but it wasn't detected in my test because of 
Richard's extra check in the for loop, limiting cstring to 128 chars.  There is 
no reason why tcp_connect() should be different from tcp_write(), as far as gcc 
is concerned.  I've made host_name_len a pointer in tcp_connect(), and now the 
host_name is passed correctly.

This works with gcc and gfortran.  I presume it wouldn't work with many other 
compilers, which secretly place the string length as a hidden argument after the 
string.
0
Reply Gib 9/2/2010 11:58:38 PM

On 8/31/2010 3:15 AM, Gib Bogle wrote:
> client.c
>
>
> /* Connect to a specified host and port.
> * Return a socket number in sock. */
>
> void tcp_connect(sock, host_name, host_name_len, port, error)
> int *sock, *port, *error;
> char *host_name;
> int host_name_len;
> {
> char cstring[129];
> int i;
> struct hostent *host_ent;
> struct sockaddr_in host;
> int keepalive;
> char *from, *to;
> WORD wver;
> WSADATA wsaData;
>

Gib, if you got this to link, then you found a way resolve
> /* Attempt connection */
> if (connect(*sock, (struct sockaddr *) &host, sizeof(host)) ==
> SOCKET_ERROR)
> {printerrormsg("Connect failed."); closesocket(*sock); return;}

this ^^^^, which I couldn't.

Possibilities:

Do you include a header which I did not?
#include <winsock.h>
#include <stdio.h>

Did you link to something on the command line to resolve it?

If your intent was to have it call this

subroutine write_error_sub(msg)
character*(*) :: msg
write(*,*) msg
end subroutine

from fortran, well, I couldn't find a way to do it:

C:\eq\source>gfortran client1.o tcpc.o  libws2_32.a fortest.f90 -o out
client1.o:client1.c:(.text+0xc4): undefined reference to `write_error_sub'

Anyways, I don't know much about what I'm doing, and it's showing.  Cheers,
-- 
Uno


0
Reply Uno 9/3/2010 12:39:41 AM

On 9/2/2010 12:59 AM, Richard Maine wrote:
> Arjen Markus<arjen.markus895@gmail.com>  wrote:
>
>>      call tcp_write(sock,msg,msglen,error)
>>
>> the argument msglen is not needed....
>    [explains the usual issue with Fortran/C character passing]
>
>> The above call should be:
>>
>>     call tcp_write(sock,msg,error)
>
> Except that I think you'll find that won't work because my tcp_write
> expects msglen to be passed by address instead of by value as will
> probably happen with most implementations (as you correctly describe).
> This is intentional. The documentation I provided in the post was
> admitedly... um... minimal. But the idea was that msg should *NOT* be a
> character string on the Fortran side. After all, character is (in my
> view, expressed here before) a poor choice for an arbitrary bit bucket.
> I tend to use arrays of integers (generally 1-byte ones) for buffers
> like this. I think you'll find that if msg is an array of integers, that
> the first form shown above is appropriate.
>
> (Yes, I know it is a pointer to char on the C side, but C is ... funny
> that way in that char is numeric.)
>
> Gib's test happened to use character data, but that's not a general
> property of tcp data buffers.
>

Well, Richard, I've been slaughtering this material today.  I don't do 
much programming over here on windows, but I'm finding the reasons that 
I had for doing so are becoming fewer.  Who knows, one day I might 
actually understand mingw.

When I couldn't find a line number in notepad, I bit the bullet and got 
notepad++, which is wonderful compared to what ii replaces.  So while 
the code you posted lays strewn around in translation units with 
unresolved references, darnit, things are getting squared.

I realized after I posted to Gib that I was leaving out part of the 
story, and this detail could really help prognosticate.  I had trouble 
on the C side, but I failed to report that I had trouble on the fortran 
side as well:

C:\DOCUME~1\dan\LOCALS~1\Temp\ccYPsO32.o:fortest.f90:(.text+0x126): 
undefined re
ference to `tcp_connect_'
collect2: ld returned 1 exit status

Anyways, so I'm hoping you're giving partial credit for trying to state 
the problem clearly.
-- 
Uno

0
Reply Uno 9/3/2010 12:59:35 AM

Uno wrote:

> Gib, if you got this to link, then you found a way resolve
>> /* Attempt connection */
>> if (connect(*sock, (struct sockaddr *) &host, sizeof(host)) ==
>> SOCKET_ERROR)
>> {printerrormsg("Connect failed."); closesocket(*sock); return;}
> 
> this ^^^^, which I couldn't.

My deepest apologies, Uno.  I stupidly chopped some code off the top of the 
client.c code when I posted it.  I guess I was trying to reduce the size by 
taking off Richard's comments.  Bugger!  I'll post it soon (have to go out now), 
and I since I've been playing around a bit testing things I want to make sure 
that what I post is right this time.  Take a break.
0
Reply Gib 9/3/2010 1:15:18 AM

Arjen Markus wrote:

> I have installed the equation.com version of gfortran and it comes
> with the
> libws_32.a library, alright. But perhaps not the very latest
> version ...

Thanks for you reply, Arjen, I was motivated to look again and found it.

How do you have this arranged so that the linker finds it when it is 
creating the executable?

I'm "new" on windows all over again.  I find that the steps you take to 
pay attention to the virtue of laziness inform what you can do to the 
other installs.

(That's almost a sentence.:-))
-- 
Uno
0
Reply Uno 9/3/2010 2:04:51 AM

On 3 sep, 01:58, Gib Bogle <g.bo...@auckland.no.spam.ac.nz> wrote:
> Arjen Markus wrote:
>
> <snipped because my newsreader puts a limit on quoted characters>
>
> >> Obviously I wasn't concentrating when I worked on this, because I am a=
ware of
> >> this string-passing issue (there was something nagging at the back of =
my mind
> >> but I ignored it). =A0Now I'm wondering why it seemed to pass the brie=
f test I
> >> gave it. =A0A puzzle that I'll have to defer until tomorrow - it's get=
ting late here.
>
> >> Gib- Tekst uit oorspronkelijk bericht niet weergeven -
>
> >> - Tekst uit oorspronkelijk bericht weergeven -
>
> > It is only the tcp_connect() routine that is important here -
> > tcp_write()
> > works as you thought.
>
> Interesting. =A0In fact tcp_connect() was not working correctly as I had =
it,
> although it appeared to. =A0host_name_len passed as an int was giving a g=
arbage
> value (a big positive number), but it wasn't detected in my test because =
of
> Richard's extra check in the for loop, limiting cstring to 128 chars. =A0=
There is
> no reason why tcp_connect() should be different from tcp_write(), as far =
as gcc
> is concerned. =A0I've made host_name_len a pointer in tcp_connect(), and =
now the
> host_name is passed correctly.
>
> This works with gcc and gfortran. =A0I presume it wouldn't work with many=
 other
> compilers, which secretly place the string length as a hidden argument af=
ter the
> string.

I know CVF places the hidden argument right after the string (by
default) and
Intel Fortran places it at the end (by default). It is something for
which I
have a heuristic test :) and I will build that into the generalised
version
(well, the test will determine the value of a C macro, so needs to run
as
part of the build process). Anyway, this kind of things is annoying
but solvable.

Regards,

Arjen
0
Reply Arjen 9/3/2010 6:35:25 AM

With any luck, this is a version of clientc.c that works with gfortran/gcc

/* $Id: clientc.c,v 1.1.1.1 2003/03/06 19:38:16 maine Exp $ */
/* $Name:  $ */

/* clientc.c
  * open a tcp connection for a getData client.
  *
  * The read/write/close routines are used in both clients and servers
  * and are in a separate file.
  *
  * This file has wrappers for the system routines that are
  * not directly or easily callable from Fortran.
  * Specific to system Fortran and C calling conventions.
  *
  * Version for MS Windows MS C and CVF.
  * Differences from nag version are:
  *   Different system include files.
  *   Different procedure name mangling convention in the defines
  *   Specify __stdcall in procedure headers.
  *   Add extern decl for write_error_sub (to get the __stdcall).
  *   Different placement of implicit string length argument.
  *   Have to call Win-specific WSAStartup or nothing works.
  *   Cast *port (perhaps appropriate for nag version also).
  *   Used SOCKET_ERROR and INVALID_SOCKET to test for errors per MS docs,
  *   though the bsd-style test did appear to work.
  *
  * 11 Oct 91, Richard Maine: Version 1.0
  * 17 Jul 01, Richard Maine: MS Windows port.
  * 3 Sep 10, slightly modified by Gib Bogle
  */

#include <sys/types.h>
#include <winsock.h>

/* Defines to make routines fortran-callable */
/*
  * Would probably be better to return an error message to the
  * calling routine instead of calling write_error_msg from in here.
  */

static int started = 0;

#define write_error_msg write_error_sub_
#define tcp_connect tcp_connect_
extern void  write_error_msg (char * msg, int n);

/* Wrapper to call fortran error message routine.
  * We want to avoid standard c i/o. */

void printerrormsg(msg)
   char *msg;
{
   write_error_msg(msg,strlen(msg));
}

/* Connect to a specified host and port.
  * Return a socket number in sock. */

void tcp_connect(sock, host_name, host_name_len, port, error)
   int *sock, *port, *error;
   char *host_name;
   int *host_name_len;	// note: this was not a pointer in RM's code
{
   char cstring[129];
   int i;
   struct hostent *host_ent;
   struct sockaddr_in host;
   int keepalive;
   char *from, *to;
   WORD wver;
   WSADATA wsaData;

   *error = 1;

   /* Start up Windows sockets */
   if (started == 0) {
     started = 1;
     wver = MAKEWORD(2,0);
     i = WSAStartup(wver, &wsaData);
   }

   /* Make host_name into a c string */
   for (i=0; (i<*host_name_len) && (i<127) && (host_name[i] != ' '); i++)
     cstring[i] = host_name[i];
   cstring[i] = '\0';

   /* Find the host IP address */
   host.sin_family = AF_INET;
   host_ent = gethostbyname(cstring);
   if (host_ent==0) {printerrormsg("Can't find host address."); return;}
   /* Avoid bcopy/memcpy dependence. */
   from = (char *) host_ent->h_addr;
   to = (char *) &host.sin_addr;
   for (i=0; i<host_ent->h_length; i++) *to++ = *from++;

   /* Set the port */
   host.sin_port = htons((unsigned short int) *port);

   /* Create a socket */
   *sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
   if (*sock==INVALID_SOCKET) {printerrormsg("Can't create socket.");
     return;
   }

   /* Attempt connection */
   if (connect(*sock, (struct sockaddr *) &host, sizeof(host)) == SOCKET_ERROR)
     {printerrormsg("Connect failed."); closesocket(*sock); return;}

   /* Enable keepalive packets to check socket connection. */
   keepalive = 1;
   setsockopt(*sock, SOL_SOCKET, SO_KEEPALIVE, (char *) &keepalive, 4);

   *error = 0;
}
0
Reply Gib 9/3/2010 7:07:58 AM

Gib Bogle <g.bogle@auckland.no.spam.ac.nz> wrote:

> With any luck, this is a version of clientc.c that works with gfortran/gcc
>
>    int *host_name_len;        // note: this was not a pointer in RM's code

I'm slightly curious about the reason for that change. I had it as a
nonpointer because host_name did seem like something that, being a name,
"naturally" ought to be character, unlike the tcp data buffers, which I
viewed as just bit buckets. Thus I played the game needed to pass a
Fortran character, which (usually) involves an extra "hidden" value
argument for the length.

That does mean I had to deal with the issues of porting the code between
compilers with differences in details such as where the extra length
argument belonged.

I suppose you probably are passing the host name as a non-character
Fortran variable in your modified version, and then passing the length
explicitly. I can see that would avoid having to deal with the
variations in character passing conventions. One would pay for it in
having to get the character name data into a non-character variable,
possibly using transfer or equivalence or some such game. I could se tht
as a tradeoff some people might prefer. Is that what you are doing?

P.S. Of course, this is all much better with the f2003 C interop stuff,
but you might not be able to count on availability of that in the
compilers you need to use. (I wouldn't hold my breath waiting for
someone to bring CVF back under active support and add that feature to
it, for example. I would expect it to get in gfortran, if it isn't
already there.)

-- 
Richard Maine                    | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle           |  -- Mark Twain
0
Reply nospam 9/3/2010 7:27:29 AM

Richard Maine wrote:

> Should anyone care, here's the comparable stuff I had for my servers. I
> did not port this to Windows, and it hasn't even been used on a wide
> variety of Unix systems - just the few we were using for servers. It
> started out on SunOS 4, ported to Solaris 2, and I think I recall
> experimenting with this on Linux.
> 
> I wrote this stuff about 20 years ago. It is currently still in wide use
> at NASA Dryden (and I don't see any sign of that changing soon).

I needed to add these includes:
#include <stdlib.h>
#include <unistd.h>

I guess I didn't need to, but for a function like exit, well, I don't 
want to go looking for new code when the c standard headers are recommended.

$ gcc -c -D_GNU_SOURCE -std=c99 -Wall -Wextra server1.c
server1.c:45: warning: unused parameter �sig�
server1.c: In function �tcp_listen_�:
server1.c:103: warning: pointer targets in passing argument 3 of 
�accept� differ in signedness
server1.c:131: warning: pointer targets in passing argument 3 of 
�getsockname� differ in signedness
server1.c:69: warning: unused variable �pid�
$ cat server1.c
/* $Id: serverc.c,v 1.2 2005/12/28 22:49:13 maine Exp $ */
/* $Name:  $ */

/* serverc.c
  * listen for a connection attempt to a getData server.
  *
  * The read/write/close routines are used in both clients and servers
  * and are in a separate file.
  *
  * This file has wrappers for the system routines that are
  * not directly or easily callable from Fortran.
  * Specific to system Fortran and C calling conventions.
  *
  * Version for SunOS 4.1.x with NAG f90 1.2.
  * Note, specifically that Sun Fortran puts character length
  * information at the end of the argument list instead of right
  * after the corresponding arguments.
  *
  * 28 Jun 93, Richard Maine: Version 1.5.
  * 19 Nov 96, Richard Maine: casts to avoid gcc warnings.
  * 16 Apr 98, Richard Maine: fix sol2 sigchld handling.
  * 2 Dec 98, Richard Maine: fix addr len in gethostbyaddr.
  * 21 Dec 05, Richard Maine: avoid sun-specific in_addr structure.
  */

#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

/* Defines to make routines fortran-callable */
#define tcp_listen tcp_listen_

/* handler for SIGCHLD signal
  * Needed so that child processes can be decently buried when they die.
  * USG systems may need signal handler reestablished after use?
  * but we are not using this for SOL2. */

void child_handler(sig)
   int sig;
{
   wait3(0, WNOHANG, 0);
   return;
}

/* Listen for connection attempts on the specified port.
  * Fork a child for each connection.
  * Return connection information.
  * Normal return value for child is 0.
  * Positive return values are errors in parent.
  * Negative return values are errors in child. */

void tcp_listen(port ,sock, client_ip, client_port, client_name,
      server_ip, connect_num, error, client_name_len)
   int *port, *sock, *client_port, *connect_num, *error;
   int client_ip[3], server_ip[3];
   char *client_name;
   int client_name_len;
{
   struct sockaddr_in server_addr, client_addr;
   int lsock; /* Socket for listening */
   int addr_size = sizeof(server_addr);
   int addr_len;
   int pid;
   int keepalive;
   struct hostent *host_ent;
   int i;
   unsigned char *ip_byte;

   /* Divorce ourselves from controlling terminal. */
   /*  See Stevens, Chapter 13. */

   if (fork()>0) exit(0);  /* Parent returns; child continues. */
   setsid();  /* Become session leader */

   /* Create a socket, bind it to specified port and listen. */

   *connect_num = 0;
   lsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
   if (lsock<0) {*error=1; return;}
   server_addr.sin_family = AF_INET;
   server_addr.sin_addr.s_addr = INADDR_ANY;
   server_addr.sin_port = htons(*port);
   if (bind(lsock, (struct sockaddr *) &server_addr, addr_size) < 0)
     {*error=2; return;}
   if (listen(lsock,5) < 0) {*error=3; return;}

   /* Accept connections and fork server instances. */

#ifdef SOL2
   signal(SIGCHLD, SIG_IGN);
#else
   signal(SIGCHLD, child_handler);
#endif

   for (;;) {
     addr_len = addr_size;
     *sock = accept(lsock, (struct sockaddr *) &client_addr, &addr_len);

     /* For reasons unclear to me, we get a lot of accept failures. */
     /* perror says something about interrupted system call. */
     /* We just ignore them for now. */
     /* Can count them by moving the connect_num incrementation. */

     if (*sock<0) continue; /* Connect failed */
     *connect_num = *connect_num + 1;

     /* Child process.  Return connection data. */
     if (fork()==0) {
       close(lsock);
       ip_byte = (unsigned char *) &client_addr.sin_addr;
       client_ip[0] = *(ip_byte++);
       client_ip[1] = *(ip_byte++);
       client_ip[2] = *(ip_byte++);
       client_ip[3] = *(ip_byte++);
       *client_port = ntohs(client_addr.sin_port);
       host_ent = gethostbyaddr((char *) &client_addr.sin_addr.s_addr,
            sizeof(client_addr.sin_addr.s_addr), AF_INET);
       for (i=0; i<client_name_len; i++) client_name[i] = ' ';
       if (host_ent) {
         for (i=0; (i<client_name_len) && (host_ent->h_name[i]!=0); i++)
           client_name[i] = host_ent->h_name[i];
       }

       addr_len = addr_size;
       getsockname(*sock, (struct sockaddr *) &server_addr, &addr_len);
       ip_byte = (unsigned char *) &server_addr.sin_addr;
       server_ip[0] = *(ip_byte++);
       server_ip[1] = *(ip_byte++);
       server_ip[2] = *(ip_byte++);
       server_ip[3] = *(ip_byte++);

       signal(SIGCHLD, SIG_DFL);

       /* We want an error return from writes to closed sockets so
        * we can shut down cleanly and log the termination.
        * Without this, we quitely die.
        */
       signal (SIGPIPE, SIG_IGN);

       /* Enable keepalive packets to check socket connection. */
       keepalive = 1;
       setsockopt(*sock, SOL_SOCKET, SO_KEEPALIVE, (char *) &keepalive, 4);

       /* Allow SIGIO/SIGURG to signal this process. */
       /* Not currently needed.  Retain as comment. */
       /*   if (fcntl(*sock, F_SETOWN, getpid()) < 0) return(-1); */
       /*   if (fcntl(*sock, F_SETFL, FASYNC) < 0) return (-2);   */

       *error=0;
       return;
     }

     /* Parent process.  Loop back for further connections. */
     close(*sock);
   }

}


// gcc -c -D_GNU_SOURCE -std=c99 -Wall -Wextra server1.c
$

Client didn't do so well as to become object code.
-- 
Uno
0
Reply Uno 9/3/2010 7:28:07 AM

Richard Maine wrote:
> Gib Bogle <g.bogle@auckland.no.spam.ac.nz> wrote:
> 
>> With any luck, this is a version of clientc.c that works with gfortran/gcc
>>
>>    int *host_name_len;        // note: this was not a pointer in RM's code
> 
> I'm slightly curious about the reason for that change. I had it as a
> nonpointer because host_name did seem like something that, being a name,
> "naturally" ought to be character, unlike the tcp data buffers, which I
> viewed as just bit buckets. Thus I played the game needed to pass a
> Fortran character, which (usually) involves an extra "hidden" value
> argument for the length.
> 
> That does mean I had to deal with the issues of porting the code between
> compilers with differences in details such as where the extra length
> argument belonged.
> 
> I suppose you probably are passing the host name as a non-character
> Fortran variable in your modified version, and then passing the length
> explicitly. I can see that would avoid having to deal with the
> variations in character passing conventions. One would pay for it in
> having to get the character name data into a non-character variable,
> possibly using transfer or equivalence or some such game. I could se tht
> as a tradeoff some people might prefer. Is that what you are doing?

When I put a printf in clientc.c to look at the value of host_name_len that was 
passed, I saw that it was 2686536 when host_name = 'localhost'.  Since Fortran 
passes all visible arguments by reference, of course that makes sense.  As I 
said in another post that you may have missed, my test program seemed to work 
because you also truncate cstring to 128 chars.  The hidden string-length 
arguments that some Fortran compilers use are passed by value, true, but since 
no problems arise with the gcc compilers, presumably the hidden arguments are at 
the end of the argument list - I must check .... Yes, when the argument 'hidden' 
is added to the end of the argument list for tcp_connect() in clientc.c, it 
receives the value 128 in my test program.  That is the size of the host_name 
character variable.

> 
> P.S. Of course, this is all much better with the f2003 C interop stuff,
> but you might not be able to count on availability of that in the
> compilers you need to use. (I wouldn't hold my breath waiting for
> someone to bring CVF back under active support and add that feature to
> it, for example. I would expect it to get in gfortran, if it isn't
> already there.)
> 

This should really all be done using the C interop stuff, I agree.  Currently 
with my other Fortran compiler (ifort) I'm using some much more complicated 
Fortran code (accessing the Windows winsock stuff directly) that someone 
supplied me with.  The C option is much cleaner, and it should be made to work 
on any modern Fortran compiler.
0
Reply Gib 9/3/2010 9:14:47 AM

On 9/3/2010 12:07 AM, Gib Bogle wrote:
> With any luck, this is a version of clientc.c that works with gfortran/gcc

C:\eq\source>gcc -c -Wall -Wextra tcpc.c

C:\eq\source>gcc -c -Wall -Wextra client1.c
client1.c: In function 'tcp_connect':
client1.c:40:3: warning: implicit declaration of function 'write_error_sub'
client1.c:25:6: warning: 'started' is used uninitialized in this function

C:\eq\source>gfortran client1.o tcpc.o  libws2_32.a fortest.f90 -o out
client1.o:client1.c:(.text+0xc4): undefined reference to `write_error_sub'
client1.o:client1.c:(.text+0x165): undefined reference to `write_error_sub'
client1.o:client1.c:(.text+0x19f): undefined reference to `write_error_sub'
C:\DOCUME~1\dan\LOCALS~1\Temp\ccIMr2tt.o:fortest.f90:(.text+0x126): 
undefined re
ference to `tcp_connect_'
collect2: ld returned 1 exit status

Lines 42 and 43 of client.c:
#define write_error_msg write_error_sub_
#define tcp_connect tcp_connect_

So is the idea here that we want to figure out how the compilers are 
going to mangle the function names?
-- 
Uno
0
Reply Uno 9/4/2010 2:59:43 AM

Uno wrote:
> On 9/3/2010 12:07 AM, Gib Bogle wrote:
>> With any luck, this is a version of clientc.c that works with 
>> gfortran/gcc
> 
> C:\eq\source>gcc -c -Wall -Wextra tcpc.c
> 
> C:\eq\source>gcc -c -Wall -Wextra client1.c
> client1.c: In function 'tcp_connect':
> client1.c:40:3: warning: implicit declaration of function 'write_error_sub'
> client1.c:25:6: warning: 'started' is used uninitialized in this function
> 
> C:\eq\source>gfortran client1.o tcpc.o  libws2_32.a fortest.f90 -o out
> client1.o:client1.c:(.text+0xc4): undefined reference to `write_error_sub'
> client1.o:client1.c:(.text+0x165): undefined reference to `write_error_sub'
> client1.o:client1.c:(.text+0x19f): undefined reference to `write_error_sub'
> C:\DOCUME~1\dan\LOCALS~1\Temp\ccIMr2tt.o:fortest.f90:(.text+0x126): 
> undefined re
> ference to `tcp_connect_'
> collect2: ld returned 1 exit status
> 
> Lines 42 and 43 of client.c:
> #define write_error_msg write_error_sub_
> #define tcp_connect tcp_connect_
> 
> So is the idea here that we want to figure out how the compilers are 
> going to mangle the function names?

Yes.  gfortran adds '_' to subroutine/function names.
0
Reply Gib 9/4/2010 5:12:25 AM

On 9/3/2010 10:12 PM, Gib Bogle wrote:

> Yes. gfortran adds '_' to subroutine/function names.

I think you're as lost as I am.  You wouldn't happen to be an 
australian, would you, because that is who you are in my head.

If you are, then bob and judy need to get to the airport.  If you 
aren't, then you need not worry.

Cheers,
-- 
Uno

0
Reply Uno 9/4/2010 6:39:33 AM

Uno wrote:
> On 9/3/2010 10:12 PM, Gib Bogle wrote:
> 
>> Yes. gfortran adds '_' to subroutine/function names.
> 
> I think you're as lost as I am.  You wouldn't happen to be an 
> australian, would you, because that is who you are in my head.
> 
> If you are, then bob and judy need to get to the airport.  If you 
> aren't, then you need not worry.
> 
> Cheers,

Frankly, I have difficulty following you.  All this socket stuff is working for 
me, with gfortran.  To embark on multi-language programming it is necessary to 
have a degree of familiarity with each language.
0
Reply Gib 9/5/2010 12:17:08 AM

Gib Bogle <g.bogle@auckland.no.spam.ac.nz> wrote:

> Uno wrote:
[something]
> 
> Frankly, I have difficulty following you.

Don't think you are alone. :-)

-- 
Richard Maine                    | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle           |  -- Mark Twain
0
Reply nospam 9/5/2010 2:10:27 AM

Richard Maine wrote:
> Gib Bogle <g.bogle@auckland.no.spam.ac.nz> wrote:
> 
>> Uno wrote:
> [something]
>> Frankly, I have difficulty following you.
> 
> Don't think you are alone. :-)
> 

It's a challenge.
0
Reply Gib 9/6/2010 6:15:24 AM

On 3 sep, 09:07, Gib Bogle <g.bo...@auckland.no.spam.ac.nz> wrote:
> With any luck, this is a version of clientc.c that works with gfortran/gc=
c
>
> /* $Id: clientc.c,v 1.1.1.1 2003/03/06 19:38:16 maine Exp $ */
> /* $Name: =A0$ */
>
> /* clientc.c
> =A0 * open a tcp connection for a getData client.
> =A0 *
> =A0 * The read/write/close routines are used in both clients and servers
> =A0 * and are in a separate file.
> =A0 *
> =A0 * This file has wrappers for the system routines that are
> =A0 * not directly or easily callable from Fortran.
> =A0 * Specific to system Fortran and C calling conventions.
> =A0 *
> =A0 * Version for MS Windows MS C and CVF.
> =A0 * Differences from nag version are:
> =A0 * =A0 Different system include files.
> =A0 * =A0 Different procedure name mangling convention in the defines
> =A0 * =A0 Specify __stdcall in procedure headers.
> =A0 * =A0 Add extern decl for write_error_sub (to get the __stdcall).
> =A0 * =A0 Different placement of implicit string length argument.
> =A0 * =A0 Have to call Win-specific WSAStartup or nothing works.
> =A0 * =A0 Cast *port (perhaps appropriate for nag version also).
> =A0 * =A0 Used SOCKET_ERROR and INVALID_SOCKET to test for errors per MS =
docs,
> =A0 * =A0 though the bsd-style test did appear to work.
> =A0 *
> =A0 * 11 Oct 91, Richard Maine: Version 1.0
> =A0 * 17 Jul 01, Richard Maine: MS Windows port.
> =A0 * 3 Sep 10, slightly modified by Gib Bogle
> =A0 */
>
> #include <sys/types.h>
> #include <winsock.h>
>
> /* Defines to make routines fortran-callable */
> /*
> =A0 * Would probably be better to return an error message to the
> =A0 * calling routine instead of calling write_error_msg from in here.
> =A0 */
>
> static int started =3D 0;
>
> #define write_error_msg write_error_sub_
> #define tcp_connect tcp_connect_
> extern void =A0write_error_msg (char * msg, int n);
>
> /* Wrapper to call fortran error message routine.
> =A0 * We want to avoid standard c i/o. */
>
> void printerrormsg(msg)
> =A0 =A0char *msg;
> {
> =A0 =A0write_error_msg(msg,strlen(msg));
>
> }
>
> /* Connect to a specified host and port.
> =A0 * Return a socket number in sock. */
>
> void tcp_connect(sock, host_name, host_name_len, port, error)
> =A0 =A0int *sock, *port, *error;
> =A0 =A0char *host_name;
> =A0 =A0int *host_name_len; =A0// note: this was not a pointer in RM's cod=
e
> {
> =A0 =A0char cstring[129];
> =A0 =A0int i;
> =A0 =A0struct hostent *host_ent;
> =A0 =A0struct sockaddr_in host;
> =A0 =A0int keepalive;
> =A0 =A0char *from, *to;
> =A0 =A0WORD wver;
> =A0 =A0WSADATA wsaData;
>
> =A0 =A0*error =3D 1;
>
> =A0 =A0/* Start up Windows sockets */
> =A0 =A0if (started =3D=3D 0) {
> =A0 =A0 =A0started =3D 1;
> =A0 =A0 =A0wver =3D MAKEWORD(2,0);
> =A0 =A0 =A0i =3D WSAStartup(wver, &wsaData);
> =A0 =A0}
>
> =A0 =A0/* Make host_name into a c string */
> =A0 =A0for (i=3D0; (i<*host_name_len) && (i<127) && (host_name[i] !=3D ' =
'); i++)
> =A0 =A0 =A0cstring[i] =3D host_name[i];
> =A0 =A0cstring[i] =3D '\0';
>
> =A0 =A0/* Find the host IP address */
> =A0 =A0host.sin_family =3D AF_INET;
> =A0 =A0host_ent =3D gethostbyname(cstring);
> =A0 =A0if (host_ent=3D=3D0) {printerrormsg("Can't find host address."); r=
eturn;}
> =A0 =A0/* Avoid bcopy/memcpy dependence. */
> =A0 =A0from =3D (char *) host_ent->h_addr;
> =A0 =A0to =3D (char *) &host.sin_addr;
> =A0 =A0for (i=3D0; i<host_ent->h_length; i++) *to++ =3D *from++;
>
> =A0 =A0/* Set the port */
> =A0 =A0host.sin_port =3D htons((unsigned short int) *port);
>
> =A0 =A0/* Create a socket */
> =A0 =A0*sock =3D socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
> =A0 =A0if (*sock=3D=3DINVALID_SOCKET) {printerrormsg("Can't create socket=
..");
> =A0 =A0 =A0return;
> =A0 =A0}
>
> =A0 =A0/* Attempt connection */
> =A0 =A0if (connect(*sock, (struct sockaddr *) &host, sizeof(host)) =3D=3D=
 SOCKET_ERROR)
> =A0 =A0 =A0{printerrormsg("Connect failed."); closesocket(*sock); return;=
}
>
> =A0 =A0/* Enable keepalive packets to check socket connection. */
> =A0 =A0keepalive =3D 1;
> =A0 =A0setsockopt(*sock, SOL_SOCKET, SO_KEEPALIVE, (char *) &keepalive, 4=
);
>
> =A0 =A0*error =3D 0;
>
>
>
> }- Tekst uit oorspronkelijk bericht niet weergeven -
>
> - Tekst uit oorspronkelijk bericht weergeven -

I have started making this code and the related code a bit more
general.
It is more or less working now with gfortran/gcc, but I ran into an
odd
problem with Intel Fortran: I can not find the correct library to use
for the sockets!

Anyone knows which library to use? (I suppose the IDE will help a bit,
have not tried that yet :))

Regards,

Arjen
0
Reply arjen.markus895 (633) 9/8/2010 7:10:26 AM

On 8 sep, 09:10, Arjen Markus <arjen.markus...@gmail.com> wrote:
> On 3 sep, 09:07, Gib Bogle <g.bo...@auckland.no.spam.ac.nz> wrote:
>
>
>
>
>
> > With any luck, this is a version of clientc.c that works with gfortran/=
gcc
>
> > /* $Id: clientc.c,v 1.1.1.1 2003/03/06 19:38:16 maine Exp $ */
> > /* $Name: =A0$ */
>
> > /* clientc.c
> > =A0 * open a tcp connection for a getData client.
> > =A0 *
> > =A0 * The read/write/close routines are used in both clients and server=
s
> > =A0 * and are in a separate file.
> > =A0 *
> > =A0 * This file has wrappers for the system routines that are
> > =A0 * not directly or easily callable from Fortran.
> > =A0 * Specific to system Fortran and C calling conventions.
> > =A0 *
> > =A0 * Version for MS Windows MS C and CVF.
> > =A0 * Differences from nag version are:
> > =A0 * =A0 Different system include files.
> > =A0 * =A0 Different procedure name mangling convention in the defines
> > =A0 * =A0 Specify __stdcall in procedure headers.
> > =A0 * =A0 Add extern decl for write_error_sub (to get the __stdcall).
> > =A0 * =A0 Different placement of implicit string length argument.
> > =A0 * =A0 Have to call Win-specific WSAStartup or nothing works.
> > =A0 * =A0 Cast *port (perhaps appropriate for nag version also).
> > =A0 * =A0 Used SOCKET_ERROR and INVALID_SOCKET to test for errors per M=
S docs,
> > =A0 * =A0 though the bsd-style test did appear to work.
> > =A0 *
> > =A0 * 11 Oct 91, Richard Maine: Version 1.0
> > =A0 * 17 Jul 01, Richard Maine: MS Windows port.
> > =A0 * 3 Sep 10, slightly modified by Gib Bogle
> > =A0 */
>
> > #include <sys/types.h>
> > #include <winsock.h>
>
> > /* Defines to make routines fortran-callable */
> > /*
> > =A0 * Would probably be better to return an error message to the
> > =A0 * calling routine instead of calling write_error_msg from in here.
> > =A0 */
>
> > static int started =3D 0;
>
> > #define write_error_msg write_error_sub_
> > #define tcp_connect tcp_connect_
> > extern void =A0write_error_msg (char * msg, int n);
>
> > /* Wrapper to call fortran error message routine.
> > =A0 * We want to avoid standard c i/o. */
>
> > void printerrormsg(msg)
> > =A0 =A0char *msg;
> > {
> > =A0 =A0write_error_msg(msg,strlen(msg));
>
> > }
>
> > /* Connect to a specified host and port.
> > =A0 * Return a socket number in sock. */
>
> > void tcp_connect(sock, host_name, host_name_len, port, error)
> > =A0 =A0int *sock, *port, *error;
> > =A0 =A0char *host_name;
> > =A0 =A0int *host_name_len; =A0// note: this was not a pointer in RM's c=
ode
> > {
> > =A0 =A0char cstring[129];
> > =A0 =A0int i;
> > =A0 =A0struct hostent *host_ent;
> > =A0 =A0struct sockaddr_in host;
> > =A0 =A0int keepalive;
> > =A0 =A0char *from, *to;
> > =A0 =A0WORD wver;
> > =A0 =A0WSADATA wsaData;
>
> > =A0 =A0*error =3D 1;
>
> > =A0 =A0/* Start up Windows sockets */
> > =A0 =A0if (started =3D=3D 0) {
> > =A0 =A0 =A0started =3D 1;
> > =A0 =A0 =A0wver =3D MAKEWORD(2,0);
> > =A0 =A0 =A0i =3D WSAStartup(wver, &wsaData);
> > =A0 =A0}
>
> > =A0 =A0/* Make host_name into a c string */
> > =A0 =A0for (i=3D0; (i<*host_name_len) && (i<127) && (host_name[i] !=3D =
' '); i++)
> > =A0 =A0 =A0cstring[i] =3D host_name[i];
> > =A0 =A0cstring[i] =3D '\0';
>
> > =A0 =A0/* Find the host IP address */
> > =A0 =A0host.sin_family =3D AF_INET;
> > =A0 =A0host_ent =3D gethostbyname(cstring);
> > =A0 =A0if (host_ent=3D=3D0) {printerrormsg("Can't find host address.");=
 return;}
> > =A0 =A0/* Avoid bcopy/memcpy dependence. */
> > =A0 =A0from =3D (char *) host_ent->h_addr;
> > =A0 =A0to =3D (char *) &host.sin_addr;
> > =A0 =A0for (i=3D0; i<host_ent->h_length; i++) *to++ =3D *from++;
>
> > =A0 =A0/* Set the port */
> > =A0 =A0host.sin_port =3D htons((unsigned short int) *port);
>
> > =A0 =A0/* Create a socket */
> > =A0 =A0*sock =3D socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
> > =A0 =A0if (*sock=3D=3DINVALID_SOCKET) {printerrormsg("Can't create sock=
et.");
> > =A0 =A0 =A0return;
> > =A0 =A0}
>
> > =A0 =A0/* Attempt connection */
> > =A0 =A0if (connect(*sock, (struct sockaddr *) &host, sizeof(host)) =3D=
=3D SOCKET_ERROR)
> > =A0 =A0 =A0{printerrormsg("Connect failed."); closesocket(*sock); retur=
n;}
>
> > =A0 =A0/* Enable keepalive packets to check socket connection. */
> > =A0 =A0keepalive =3D 1;
> > =A0 =A0setsockopt(*sock, SOL_SOCKET, SO_KEEPALIVE, (char *) &keepalive,=
 4);
>
> > =A0 =A0*error =3D 0;
>
> > }- Tekst uit oorspronkelijk bericht niet weergeven -
>
> > - Tekst uit oorspronkelijk bericht weergeven -
>
> I have started making this code and the related code a bit more
> general.
> It is more or less working now with gfortran/gcc, but I ran into an
> odd
> problem with Intel Fortran: I can not find the correct library to use
> for the sockets!
>
> Anyone knows which library to use? (I suppose the IDE will help a bit,
> have not tried that yet :))
>
> Regards,
>
> Arjen- Tekst uit oorspronkelijk bericht niet weergeven -
>
> - Tekst uit oorspronkelijk bericht weergeven -

With some small adjustments I have the client side almost working on
Linux
as well (both gfortran and Intel Fortran, by the way).

Regards,

Arjen
0
Reply arjen.markus895 (633) 9/8/2010 11:11:04 AM

Arjen Markus wrote:

> With some small adjustments I have the client side almost working on
> Linux
> as well (both gfortran and Intel Fortran, by the way).
> 
> Regards,
> 
> Arjen

I'm also using it with gfortran on Windows (with MinGW) and Linux.  I haven't 
looked at ifort, since I have some Fortran code that uses the Win API that is 
working.  I'd like to replace this by a C-based version, though, to make 
everything as uniform and portable as possible.  I'm in the process of porting 
my application to Mac OS X, on which I expect clientc.c to work pretty much the 
same as in Linux.
0
Reply Gib 9/8/2010 9:12:58 PM

Gib Bogle wrote:

> It's a challenge.

Of course it's a challenge to communicate a half-world away.  It's 
harder for me to understand this notion since I have little experience 
with client/server communication.  I have clients and servers, but 
they're people like bob, judy, ginger, sandy or jimmy.

I think the target for Gib's original thesis was for windows.  Richard 
posted this for linux.  My question is simple:

What are you supposed to do with this and why does fortran make this easier?

A lot of these warnings will disappear pretty quickly, but without the 
author's intent being known, I don't know how to proceed.


$ gcc -c -Wall -Wextra client2.c
client2.c:43: warning: unused parameter �sig�
client2.c: In function �tcp_listen_�:
client2.c:76: warning: implicit declaration of function �fork�
client2.c:76: warning: implicit declaration of function �exit�
client2.c:76: warning: incompatible implicit declaration of built-in 
function �exit�
client2.c:77: warning: implicit declaration of function �setsid�
client2.c:101: warning: pointer targets in passing argument 3 of 
�accept� differ in signedness
client2.c:113: warning: implicit declaration of function �close�
client2.c:129: warning: pointer targets in passing argument 3 of 
�getsockname� differ in signedness
client2.c:67: warning: unused variable �pid�
$  gcc -c -D_GNU_SOURCE -std=c99 -Wall -Wextra server1.c
server1.c:45: warning: unused parameter �sig�
server1.c: In function �tcp_listen_�:
server1.c:103: warning: pointer targets in passing argument 3 of 
�accept� differ in signedness
server1.c:131: warning: pointer targets in passing argument 3 of 
�getsockname� differ in signedness
server1.c:69: warning: unused variable �pid�
$ cat client2.c
/* $Id: serverc.c,v 1.2 2005/12/28 22:49:13 maine Exp $ */
/* $Name:  $ */

/* serverc.c
  * listen for a connection attempt to a getData server.
  *
  * The read/write/close routines are used in both clients and servers
  * and are in a separate file.
  *
  * This file has wrappers for the system routines that are
  * not directly or easily callable from Fortran.
  * Specific to system Fortran and C calling conventions.
  *
  * Version for SunOS 4.1.x with NAG f90 1.2.
  * Note, specifically that Sun Fortran puts character length
  * information at the end of the argument list instead of right
  * after the corresponding arguments.
  *
  * 28 Jun 93, Richard Maine: Version 1.5.
  * 19 Nov 96, Richard Maine: casts to avoid gcc warnings.
  * 16 Apr 98, Richard Maine: fix sol2 sigchld handling.
  * 2 Dec 98, Richard Maine: fix addr len in gethostbyaddr.
  * 21 Dec 05, Richard Maine: avoid sun-specific in_addr structure.
  */

#include <sys/types.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

/* Defines to make routines fortran-callable */
#define tcp_listen tcp_listen_

/* handler for SIGCHLD signal
  * Needed so that child processes can be decently buried when they die.
  * USG systems may need signal handler reestablished after use?
  * but we are not using this for SOL2. */

void child_handler(sig)
   int sig;
{
   wait3(0, WNOHANG, 0);
   return;
}

/* Listen for connection attempts on the specified port.
  * Fork a child for each connection.
  * Return connection information.
  * Normal return value for child is 0.
  * Positive return values are errors in parent.
  * Negative return values are errors in child. */

void tcp_listen(port ,sock, client_ip, client_port, client_name,
      server_ip, connect_num, error, client_name_len)
   int *port, *sock, *client_port, *connect_num, *error;
   int client_ip[3], server_ip[3];
   char *client_name;
   int client_name_len;
{
   struct sockaddr_in server_addr, client_addr;
   int lsock; /* Socket for listening */
   int addr_size = sizeof(server_addr);
   int addr_len;
   int pid;
   int keepalive;
   struct hostent *host_ent;
   int i;
   unsigned char *ip_byte;

   /* Divorce ourselves from controlling terminal. */
   /*  See Stevens, Chapter 13. */

   if (fork()>0) exit(0);  /* Parent returns; child continues. */
   setsid();  /* Become session leader */

   /* Create a socket, bind it to specified port and listen. */

   *connect_num = 0;
   lsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
   if (lsock<0) {*error=1; return;}
   server_addr.sin_family = AF_INET;
   server_addr.sin_addr.s_addr = INADDR_ANY;
   server_addr.sin_port = htons(*port);
   if (bind(lsock, (struct sockaddr *) &server_addr, addr_size) < 0)
     {*error=2; return;}
   if (listen(lsock,5) < 0) {*error=3; return;}

   /* Accept connections and fork server instances. */

#ifdef SOL2
   signal(SIGCHLD, SIG_IGN);
#else
   signal(SIGCHLD, child_handler);
#endif

   for (;;) {
     addr_len = addr_size;
     *sock = accept(lsock, (struct sockaddr *) &client_addr, &addr_len);

     /* For reasons unclear to me, we get a lot of accept failures. */
     /* perror says something about interrupted system call. */
     /* We just ignore them for now. */
     /* Can count them by moving the connect_num incrementation. */

     if (*sock<0) continue; /* Connect failed */
     *connect_num = *connect_num + 1;

     /* Child process.  Return connection data. */
     if (fork()==0) {
       close(lsock);
       ip_byte = (unsigned char *) &client_addr.sin_addr;
       client_ip[0] = *(ip_byte++);
       client_ip[1] = *(ip_byte++);
       client_ip[2] = *(ip_byte++);
       client_ip[3] = *(ip_byte++);
       *client_port = ntohs(client_addr.sin_port);
       host_ent = gethostbyaddr((char *) &client_addr.sin_addr.s_addr,
            sizeof(client_addr.sin_addr.s_addr), AF_INET);
       for (i=0; i<client_name_len; i++) client_name[i] = ' ';
       if (host_ent) {
         for (i=0; (i<client_name_len) && (host_ent->h_name[i]!=0); i++)
           client_name[i] = host_ent->h_name[i];
       }

       addr_len = addr_size;
       getsockname(*sock, (struct sockaddr *) &server_addr, &addr_len);
       ip_byte = (unsigned char *) &server_addr.sin_addr;
       server_ip[0] = *(ip_byte++);
       server_ip[1] = *(ip_byte++);
       server_ip[2] = *(ip_byte++);
       server_ip[3] = *(ip_byte++);

       signal(SIGCHLD, SIG_DFL);

       /* We want an error return from writes to closed sockets so
        * we can shut down cleanly and log the termination.
        * Without this, we quitely die.
        */
       signal (SIGPIPE, SIG_IGN);

       /* Enable keepalive packets to check socket connection. */
       keepalive = 1;
       setsockopt(*sock, SOL_SOCKET, SO_KEEPALIVE, (char *) &keepalive,
4);

       /* Allow SIGIO/SIGURG to signal this process. */
       /* Not currently needed.  Retain as comment. */
       /*   if (fcntl(*sock, F_SETOWN, getpid()) < 0) return(-1); */
       /*   if (fcntl(*sock, F_SETFL, FASYNC) < 0) return (-2);   */

       *error=0;
       return;
     }

     /* Parent process.  Loop back for further connections. */
     close(*sock);
   }

}

// gcc -c -Wall -Wextra client2.c
$ cat server1.c
/* $Id: serverc.c,v 1.2 2005/12/28 22:49:13 maine Exp $ */
/* $Name:  $ */

/* serverc.c
  * listen for a connection attempt to a getData server.
  *
  * The read/write/close routines are used in both clients and servers
  * and are in a separate file.
  *
  * This file has wrappers for the system routines that are
  * not directly or easily callable from Fortran.
  * Specific to system Fortran and C calling conventions.
  *
  * Version for SunOS 4.1.x with NAG f90 1.2.
  * Note, specifically that Sun Fortran puts character length
  * information at the end of the argument list instead of right
  * after the corresponding arguments.
  *
  * 28 Jun 93, Richard Maine: Version 1.5.
  * 19 Nov 96, Richard Maine: casts to avoid gcc warnings.
  * 16 Apr 98, Richard Maine: fix sol2 sigchld handling.
  * 2 Dec 98, Richard Maine: fix addr len in gethostbyaddr.
  * 21 Dec 05, Richard Maine: avoid sun-specific in_addr structure.
  */

#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

/* Defines to make routines fortran-callable */
#define tcp_listen tcp_listen_

/* handler for SIGCHLD signal
  * Needed so that child processes can be decently buried when they die.
  * USG systems may need signal handler reestablished after use?
  * but we are not using this for SOL2. */

void child_handler(sig)
   int sig;
{
   wait3(0, WNOHANG, 0);
   return;
}

/* Listen for connection attempts on the specified port.
  * Fork a child for each connection.
  * Return connection information.
  * Normal return value for child is 0.
  * Positive return values are errors in parent.
  * Negative return values are errors in child. */

void tcp_listen(port ,sock, client_ip, client_port, client_name,
      server_ip, connect_num, error, client_name_len)
   int *port, *sock, *client_port, *connect_num, *error;
   int client_ip[3], server_ip[3];
   char *client_name;
   int client_name_len;
{
   struct sockaddr_in server_addr, client_addr;
   int lsock; /* Socket for listening */
   int addr_size = sizeof(server_addr);
   int addr_len;
   int pid;
   int keepalive;
   struct hostent *host_ent;
   int i;
   unsigned char *ip_byte;

   /* Divorce ourselves from controlling terminal. */
   /*  See Stevens, Chapter 13. */

   if (fork()>0) exit(0);  /* Parent returns; child continues. */
   setsid();  /* Become session leader */

   /* Create a socket, bind it to specified port and listen. */

   *connect_num = 0;
   lsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
   if (lsock<0) {*error=1; return;}
   server_addr.sin_family = AF_INET;
   server_addr.sin_addr.s_addr = INADDR_ANY;
   server_addr.sin_port = htons(*port);
   if (bind(lsock, (struct sockaddr *) &server_addr, addr_size) < 0)
     {*error=2; return;}
   if (listen(lsock,5) < 0) {*error=3; return;}

   /* Accept connections and fork server instances. */

#ifdef SOL2
   signal(SIGCHLD, SIG_IGN);
#else
   signal(SIGCHLD, child_handler);
#endif

   for (;;) {
     addr_len = addr_size;
     *sock = accept(lsock, (struct sockaddr *) &client_addr, &addr_len);

     /* For reasons unclear to me, we get a lot of accept failures. */
     /* perror says something about interrupted system call. */
     /* We just ignore them for now. */
     /* Can count them by moving the connect_num incrementation. */

     if (*sock<0) continue; /* Connect failed */
     *connect_num = *connect_num + 1;

     /* Child process.  Return connection data. */
     if (fork()==0) {
       close(lsock);
       ip_byte = (unsigned char *) &client_addr.sin_addr;
       client_ip[0] = *(ip_byte++);
       client_ip[1] = *(ip_byte++);
       client_ip[2] = *(ip_byte++);
       client_ip[3] = *(ip_byte++);
       *client_port = ntohs(client_addr.sin_port);
       host_ent = gethostbyaddr((char *) &client_addr.sin_addr.s_addr,
            sizeof(client_addr.sin_addr.s_addr), AF_INET);
       for (i=0; i<client_name_len; i++) client_name[i] = ' ';
       if (host_ent) {
         for (i=0; (i<client_name_len) && (host_ent->h_name[i]!=0); i++)
           client_name[i] = host_ent->h_name[i];
       }

       addr_len = addr_size;
       getsockname(*sock, (struct sockaddr *) &server_addr, &addr_len);
       ip_byte = (unsigned char *) &server_addr.sin_addr;
       server_ip[0] = *(ip_byte++);
       server_ip[1] = *(ip_byte++);
       server_ip[2] = *(ip_byte++);
       server_ip[3] = *(ip_byte++);

       signal(SIGCHLD, SIG_DFL);

       /* We want an error return from writes to closed sockets so
        * we can shut down cleanly and log the termination.
        * Without this, we quitely die.
        */
       signal (SIGPIPE, SIG_IGN);

       /* Enable keepalive packets to check socket connection. */
       keepalive = 1;
       setsockopt(*sock, SOL_SOCKET, SO_KEEPALIVE, (char *) &keepalive, 4);

       /* Allow SIGIO/SIGURG to signal this process. */
       /* Not currently needed.  Retain as comment. */
       /*   if (fcntl(*sock, F_SETOWN, getpid()) < 0) return(-1); */
       /*   if (fcntl(*sock, F_SETFL, FASYNC) < 0) return (-2);   */

       *error=0;
       return;
     }

     /* Parent process.  Loop back for further connections. */
     close(*sock);
   }

}


// gcc -c -D_GNU_SOURCE -std=c99 -Wall -Wextra server1.c
$
-- 
Uno
0
Reply Uno 9/10/2010 7:40:51 AM

Uno wrote:
> Gib Bogle wrote:
> 
>> It's a challenge.
> 
> Of course it's a challenge to communicate a half-world away.  It's 
> harder for me to understand this notion since I have little experience 
> with client/server communication.  I have clients and servers, but 
> they're people like bob, judy, ginger, sandy or jimmy.
> 
> I think the target for Gib's original thesis was for windows.  Richard 
> posted this for linux.  My question is simple:
> 
> What are you supposed to do with this and why does fortran make this 
> easier?

Fortran doesn't make using sockets easier, just the reverse.  I wanted a way to 
communicate between my GUI written in C++ (using Qt, and multi-threaded) and my 
number-crunching program, written in Fortran.  There are other ways to achieve 
this, but I decided to use sockets.  It's very easy to get sockets working in C, 
and calling the C socket functions from Fortran turns out to be a quick route to 
having sockets in Fortran.  If you are really interested in sockets and all 
that, the classic book is Stevens's Unix Network Programming
http://www.kohala.com/start/unpv12e.html
0
Reply Gib 9/12/2010 8:40:59 AM

47 Replies
1014 Views

(page loaded in 3.051 seconds)

Similiar Articles:


















7/19/2012 3:15:14 PM


Reply: