cat > common.h << "EOF"
#ifndef __common_h
#define __common_h
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/socket.h> /* basic socket definitions */
#include <netinet/in.h>
#include <arpa/inet.h>
#include "inet.h"
#define MAXLINE 4096 /* max text line length */
static char sendline[MAXLINE], /* write buffer */
recvline[MAXLINE + 1]; /* reaad buffer */
void err_dump(const char *, ...);
void err_sys(const char *, ...);
void str_cli(register FILE*, register int sockfd);
void str_echo(int sockfd);
void dg_cli(FILE* fp, int sockfd,
struct sockaddr* pserv_addr,
int servlen);
void dg_echo(int sockfd,
struct sockaddr* pcli_addr,
int maxclilen);
#endif
EOF
cat > dgcli.c << "EOF"
/* Read the contents of the FILE *fp, write each line to the
* datagram socket, then read a line back from the datagram
* socket and write it to the standard output.
* Return to caller when an EOF is encountered on the input file.
*/
#include "inet.h"
void dg_cli(FILE* fp, int sockfd,
struct sockaddr* pserv_addr, // ptr to appropriate sockaddr_XX structure
int servlen) { // actual sizeof(*pserv_addr)
int n;
while (fgets(sendline, MAXLINE, fp) != NULL) {
n = strlen(sendline);
if (sendto(sockfd, sendline, n, 0, pserv_addr, servlen) != n)
err_dump("dg_cli: sendto error on socket");
// Now read a message from the socket and
// write it to our standard output.
n = recvfrom(sockfd, recvline, MAXLINE, 0,
(struct sockaddr*)0, (socklen_t*)0);
if (n < 0)
err_dump("dg_cli: recvfrom error");
recvline[n] = 0; /* null terminate */
fputs(recvline, stdout);
}
if (ferror(fp))
err_dump("dg_cli: error reading file");
}
EOF
cat > dgecho.c << "EOF"
/* Read a datagram from a connectionless socket and write it back to
* the sender.
* We never return, as we never know when a datagram client is done.
*/
#include "inet.h"
void dg_echo(int sockfd,
struct sockaddr* pcli_addr, /* ptr to appropriate sockaddr_XX structure */
int maxclilen) { /* sizeof(*pcli_addr) */
for (;;) {
socklen_t clilen = maxclilen;
int n = recvfrom(sockfd, recvline, MAXLINE, 0, pcli_addr, &clilen);
if (n < 0) err_dump("dg_echo: recvfrom error");
if (sendto(sockfd, recvline, n, 0, pcli_addr, clilen) != n)
err_dump("dg_echo: sendto error");
}
}
cat > udpcli.c << "EOF"
/* Example of client using UDP protocol. */
#include "inet.h"
int main(int argc, char* argv[]) {
int sockfd;
/* Open a UDP socket (an Internet datagram socket). */
if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
err_dump("client: can't open datagram socket");
struct sockaddr_in serv_addr;
/* Fill in the structure "serv_addr" with the address
* of the server that we want to send to. */
bzero((char*)&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr(SERV_HOST_ADDR);
serv_addr.sin_port = htons(SERV_UDP_PORT);
dg_cli(stdin, sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
close(sockfd);
exit(0);
}
EOF
cat > udpserv.c << "EOF"
// Example of server using UDP protocol.
#include "inet.h"
int main(int argc, char* argv[] ) {
/* Open a UDP socket (an Internet datagram socket). */
int sockfd;
if((sockfd = socket(AF_INET, SOCK_DGRAM, 0 ) ) < 0 )
err_dump("server: can't open datagram socket" );
/* Bind our local address so that the client can send to us. */
struct sockaddr_in serv_addr;
bzero((char*)&serv_addr, sizeof(serv_addr ) );
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY );
serv_addr.sin_port = htons(SERV_UDP_PORT );
if(bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr ) ) < 0 )
err_dump("server: can't bind local address" );
dg_echo(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr ) );
}
EOF
cat > error.c << "EOF"
#include "common.h"
#include <stdarg.h> /* ANSI C header file */
#include <syslog.h> /* for syslog() */
int daemon_proc; /* set nonzero by daemon_init() */
static void err_doit(int, int, const char *, va_list);
/* Fatal error related to a system call.
* Print a message and terminate. */
void err_sys(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
err_doit(1, LOG_ERR, fmt, ap);
va_end(ap);
exit(1);
}
/* Fatal error related to a system call.
* Print a message, dump core, and terminate. */
void err_dump(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
err_doit(1, LOG_ERR, fmt, ap);
va_end(ap);
abort(); /* dump core and terminate */
exit(1); /* shouldn't get here */
}
/* Print a message and return to caller.
* Caller specifies "errnoflag" and "level". */
static void err_doit(int errnoflag, int level, const char *fmt, va_list ap) {
int errno_save, n;
char buf[MAXLINE];
errno_save = errno; /* value caller might want printed */
#ifdef HAVE_VSNPRINTF
vsnprintf(buf, sizeof(buf), fmt, ap); /* this is safe */
#else
vsprintf(buf, fmt, ap); /* this is not safe */
#endif
n = strlen(buf);
if (errnoflag)
snprintf(buf + n, sizeof(buf) - n, ": %s", strerror(errno_save));
strcat(buf, "\n");
if (daemon_proc) {
syslog(level, buf, "cli-serv : %s");
} else {
fflush(stdout); /* in case stdout and stderr are the same */
fputs(buf, stderr);
fflush(stderr);
}
return;
}
EOF
cat > inet.h << "EOF"
/* Definitions for TCP and UDP client/server programs. */
#include "common.h"
#define SERV_UDP_PORT 60000
#define SERV_TCP_PORT 60000
//#define SERV_HOST_ADDR "192.168.1.13" /* host addr for server */
#define SERV_HOST_ADDR "127.0.0.1" /* host addr for server */
ssize_t readline(int fd, void *vptr, size_t maxlen);
ssize_t writen(int fd, const void *vptr, size_t n);
EOF
cat > Makefile << "EOF"
MYLIB = error.o writen.o readline.o
#LIBS =
CFLAGS = -O -Wall -Wno-unused-variable
all: $(MYLIB) tcp udp unixstr unixdg sockopt
rm -f *.o
lib: $(MYLIB)
# Internet stream version (TCP protocol).
tcp: tcpserv tcpcli
tcpcli.o tcpserv.o: inet.h common.h
tcpserv: tcpserv.o strecho.o
$(CC) $(CFLAGS) -o $@ tcpserv.o strecho.o $(MYLIB)
tcpcli: tcpcli.o strcli.o
$(CC) $(CFLAGS) -o $@ tcpcli.o strcli.o $(MYLIB)
# Internet datagram version (UDP protocol).
udp: udpserv udpcli
udpcli.o udpserv.o: inet.h common.h
udpserv: udpserv.o dgecho.o
$(CC) $(CFLAGS) -o $@ udpserv.o dgecho.o $(MYLIB)
udpcli: udpcli.o dgcli.o
$(CC) $(CFLAGS) -o $@ udpcli.o dgcli.o $(MYLIB)
# UNIX stream version.
unixstr: unixstrserv unixstrcli
unixstrcli.o unixstrserv.o: unix.h common.h
unixstrserv: unixstrserv.o strecho.o
$(CC) $(CFLAGS) -o $@ unixstrserv.o strecho.o $(MYLIB)
unixstrcli: unixstrcli.o strcli.o
$(CC) $(CFLAGS) -o $@ unixstrcli.o strcli.o $(MYLIB)
# UNIX datagram version.
unixdg: unixdgserv unixdgcli
unixdgcli.o unixdgserv.o: unix.h common.h
unixdgserv: unixdgserv.o dgecho.o
$(CC) $(CFLAGS) -o $@ unixdgserv.o dgecho.o $(MYLIB)
unixdgcli: unixdgcli.o dgcli.o
$(CC) $(CFLAGS) -o $@ unixdgcli.o dgcli.o $(MYLIB)
sockopt: sockopt.o common.h
$(CC) $(CFLAGS) -o $@ sockopt.o $(MYLIB)
clean disclean:
-rm -f *.o core a.out temp*.* \
tcpserv tcpcli udpserv udpcli \
unixstrserv unixstrcli unixdgserv unixdgcli \
s.unixdg s.unixstr sockopt
EOF
# Исправить восемь пробелов на TAB
sed -i 's/ /\t\t/g' Makefile
cat > readline.c << "EOF"
#include "common.h"
static ssize_t my_read(int fd, char *ptr) {
static int read_cnt = 0;
static char *read_ptr;
static char read_buf[MAXLINE];
if (read_cnt <= 0) {
again:
if ((read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0) {
if (errno == EINTR) goto again;
return(-1);
} else if (read_cnt == 0)
return(0);
read_ptr = read_buf;
}
read_cnt--;
*ptr = *read_ptr++;
return(1);
}
ssize_t readline(int fd, void *vptr, size_t maxlen) {
int n, rc;
char c, *ptr;
ptr = vptr;
for (n = 1; n < maxlen; n++) {
if ((rc = my_read(fd, &c)) == 1) {
*ptr++ = c;
if (c == '\n') break; /* newline is stored, like fgets() */
} else if (rc == 0) {
if(n == 1) return(0); /* EOF, no data read */
else break; /* EOF, some data was read */
} else return(-1); /* error, errno set by read() */
}
*ptr = 0; /* null terminate like fgets() */
return(n);
}
EOF
cat > sockopt.c << "EOF"
/* Example of getsockopt() and setsockopt(). */
#include "common.h"
#include <sys/types.h>
#include <sys/socket.h> /* for SOL_SOCKET and SO_xx values */
#include <netinet/in.h> /* for IPPROTO_TCP value */
#include <netinet/tcp.h> /* for TCP_MAXSEG value */
int main() {
int sockfd, maxseg, sendbuff; //, optlen;
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
err_sys("can't create socket");
/* Fetch and print the TCP maximum segment size. */
socklen_t optlen = sizeof(maxseg);
if (getsockopt(sockfd, IPPROTO_TCP, TCP_MAXSEG, (char*)&maxseg, &optlen) < 0)
err_sys("TCP_MAXSEG getsockopt error");
printf("TCP maxseg = %d\n", maxseg);
/* Set the send buffer size, then fetch it and print its value. */
sendbuff = 16384; /* just some number for example purposes */
if (setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF,
(char*)&sendbuff, sizeof(sendbuff)) < 0)
err_sys("SO_SNDBUF setsockopt error");
optlen = sizeof(sendbuff);
if (getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF,
(char*)&sendbuff, &optlen) < 0)
err_sys("SO_SNDBUF getsockopt error");
printf("send buffer size = %d\n", sendbuff);
}
EOF
cat > strcli.c << "EOF"
/* Read the contents of the FILE *fp, write each line to the
* stream socket (to the server process), then read a line back from
* the socket and write it to the standard output.
* Return to caller when an EOF is encountered on the input file.
*/
#include "common.h"
void str_cli(register FILE* fp, register int sockfd) {
int n;
while (fgets(sendline, MAXLINE, fp) != NULL) {
n = strlen(sendline);
if (writen(sockfd, sendline, n) != n)
err_sys("str_cli: writen error on socket");
/* Now read a line from the socket and
* write it to our standard output. */
n = readline(sockfd, recvline, MAXLINE);
if (n < 0) err_dump("str_cli: readline error");
recvline[n] = 0; /* null terminate */
fputs(recvline, stdout);
}
if (ferror(fp))
err_sys("str_cli: error reading file");
}
EOF
cat > strecho.c << "EOF"
/* Read a stream socket one line at a time, and write each line back
* to the sender.
* Return when the connection is terminated.
*/
#include "common.h"
void str_echo(int sockfd) {
int n;
for (;;) {
n = readline(sockfd, recvline, MAXLINE);
if (n == 0) return; /* connection terminated */
else if (n < 0) err_dump("str_echo: readline error");
if (writen(sockfd, recvline, n) != n)
err_dump("str_echo: writen error");
}
}
EOF
cat > tcpcli.c << "EOF"
/* Example of client using TCP protocol. */
#include "inet.h"
int main(int argc, char* argv[]) {
int sockfd; // TCP сокет
struct sockaddr_in serv_addr; // заполнить структуру адреса сервера
bzero((char*)&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr(SERV_HOST_ADDR);
serv_addr.sin_port = htons(SERV_TCP_PORT);
/* Open a TCP socket (an Internet stream socket). */
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
err_sys("client: can't open stream socket");
/* Connect to the server. */
if (connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0)
err_sys("client: can't connect to server");
str_cli(stdin, sockfd); // цикл обменов с сервером
close(sockfd);
exit(0);
}
EOF
cat > tcpserv.c << "EOF"
/* Example of server using TCP protocol. */
#include "inet.h"
int main(int argc, char* argv[]) {
int sockfd; // TCP сокет
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
err_dump("server: can't open stream socket");
struct sockaddr_in serv_addr; // инициализировать униадресом
bzero((char*)&serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(SERV_TCP_PORT);
if (bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0)
err_dump("server: can't bind local address");
listen(sockfd, 5);
for (;;) { // цикл по подключения
socklen_t clilen = sizeof(serv_addr);
int childpid, newsockfd;
newsockfd = accept(sockfd, (struct sockaddr*)&serv_addr, &clilen);
if (newsockfd < 0) // ожидать соединения
err_dump("server: accept error");
if ((childpid = fork()) < 0)
err_dump("server: fork error");
else if (childpid == 0) { // обрабатывать в дочернем процессе
close(sockfd); // закрыть копию прослушивающего сокета
str_echo(newsockfd); // ретранслировать полученные данные
exit(0); // завершить дочерний процесс
}
close(newsockfd); // в роительском процессе
}
}
EOF
cat > unixdgcli.c << "EOF"
/* Example of client using UNIX domain datagram protocol. */
#include "unix.h"
int main(int argc, char* argv[]) {
int sockfd, clilen, servlen;
char *mktemp();
struct sockaddr_un cli_addr, serv_addr;
/* Fill in the structure "serv_addr" with the address
* of the server that we want to send to. */
bzero((char*)&serv_addr, sizeof(serv_addr));
serv_addr.sun_family = AF_UNIX;
strcpy(serv_addr.sun_path, UNIXDG_PATH);
servlen = sizeof(serv_addr.sun_family) + strlen(serv_addr.sun_path);
/* Open a socket (a UNIX domain datagram socket). */
if ((sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
err_dump("client: can't open datagram socket");
/* Bind a local address for us.
* In the UNIX domain we have to choose our own name (that
* should be unique). We'll use mktemp() to create a unique
* pathname, based on our process id.
*/
bzero((char*)&cli_addr, sizeof(cli_addr)); /* zero out */
cli_addr.sun_family = AF_UNIX;
strcpy(cli_addr.sun_path, UNIXDG_TMP);
mktemp(cli_addr.sun_path);
clilen = sizeof(cli_addr.sun_family) + strlen(cli_addr.sun_path);
if (bind(sockfd, (struct sockaddr*)&cli_addr, clilen) < 0)
err_dump("client: can't bind local address");
dg_cli(stdin, sockfd, (struct sockaddr*)&serv_addr, servlen);
close(sockfd);
unlink(cli_addr.sun_path);
exit(0);
}
EOF
cat > unixdgserv.c << "EOF"
/* Example of server using UNIX domain datagram protocol. */
#include "unix.h"
int main(int argc, char* argv[]) {
int sockfd, servlen;
struct sockaddr_un serv_addr, cli_addr;
/* Open a socket (a UNIX domain datagram socket). */
if ((sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
err_dump("server: can't open datagram socket");
/* Bind our local address so that the client can send to us. */
unlink(UNIXDG_PATH); /* in case it was left from last time */
bzero((char*)&serv_addr, sizeof(serv_addr));
serv_addr.sun_family = AF_UNIX;
strcpy(serv_addr.sun_path, UNIXDG_PATH);
servlen = sizeof(serv_addr.sun_family) + strlen(serv_addr.sun_path);
if (bind(sockfd, (struct sockaddr*)&serv_addr, servlen) < 0)
err_dump("server: can't bind local address");
dg_echo(sockfd, (struct sockaddr*)&cli_addr, sizeof(cli_addr));
}
EOF
cat > unix.h << "EOF"
/*
* Definitions for UNIX domain stream and datagram client/server programs.
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include "common.h"
#define UNIXSTR_PATH "./s.unixstr"
#define UNIXDG_PATH "./s.unixdg"
#define UNIXDG_TMP "/tmp/dg.XXXXXX"
char *pname;
EOF
cat > unixstrcli.c << "EOF"
/* Example of client using UNIX domain stream protocol. */
#include "unix.h"
int main(int argc, char* argv[]) {
int sockfd, servlen;
struct sockaddr_un serv_addr;
/* Fill in the structure "serv_addr" with the address
* of the server that we want to send to. */
bzero((char*)&serv_addr, sizeof(serv_addr));
serv_addr.sun_family = AF_UNIX;
strcpy(serv_addr.sun_path, UNIXSTR_PATH);
servlen = strlen(serv_addr.sun_path) + sizeof(serv_addr.sun_family);
/* Open a socket (an UNIX domain stream socket). */
if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
err_sys("client: can't open stream socket");
/* Connect to the server. */
if (connect(sockfd, (struct sockaddr*)&serv_addr, servlen) < 0)
err_sys("client: can't connect to server");
str_cli(stdin, sockfd); /* do it all */
close(sockfd);
exit(0);
}
EOF
cat > unixstrserv.c << "EOF"
/* Example of server using UNIX domain stream protocol. */
#include "unix.h"
int main(int argc, char* argv[]) {
int sockfd, newsockfd, childpid, servlen;
struct sockaddr_un cli_addr, serv_addr;
/* Open a socket (a UNIX domain stream socket). */
if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
err_dump("server: can't open stream socket");
/* Bind our local address so that the client can send to us. */
bzero((char*)&serv_addr, sizeof(serv_addr));
serv_addr.sun_family = AF_UNIX;
strcpy(serv_addr.sun_path, UNIXSTR_PATH);
servlen = strlen(serv_addr.sun_path) + sizeof(serv_addr.sun_family);
if (bind(sockfd, (struct sockaddr*)&serv_addr, servlen) < 0)
err_dump("server: can't bind local address");
listen(sockfd, 5);
for (; ;) {
/* Wait for a connection from a client process.
* This is an example of a concurrent server. */
socklen_t clilen = sizeof(cli_addr);
newsockfd = accept(sockfd, (struct sockaddr*)&cli_addr, &clilen);
if (newsockfd < 0) err_dump("server: accept error");
if ((childpid = fork()) < 0) err_dump("server: fork error");
else if (childpid == 0) { /* child process */
close(sockfd); /* close original socket */
str_echo(newsockfd); /* process the request */
exit(0);
}
close(newsockfd); /* parent process */
}
}
EOF
cat > writen.c << "EOF"
#include "common.h"
/* Write "n" bytes to a descriptor */
ssize_t writen(int fd, const void *vptr, size_t n) {
size_t nleft;
ssize_t nwritten;
nleft = n;
while (nleft > 0) {
if ((nwritten = write(fd, vptr, nleft)) <= 0) {
if (errno == EINTR) nwritten = 0; /* and call write() again */
else return(-1); /* error */
}
nleft -= nwritten;
vptr += nwritten;
}
return(n);
}
EOF
Для компиляции используй:
make
Использование:
./udpserv
./udpcli
./tcpserv
./tcpcli
./unixdgserv
./unixdgcli
./unixstrserv
./unixstrcli
./sockopt