Skip to content

Commit

Permalink
Better comments, enhance connect-only.c.
Browse files Browse the repository at this point in the history
  • Loading branch information
Jan Pechanec committed Dec 12, 2017
1 parent 4591146 commit 8833e60
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 36 deletions.
45 changes: 32 additions & 13 deletions select/connect-only.c
@@ -1,10 +1,14 @@
/*
* Connect only. To show what happens if the remote side starts writing but we
* do not read. Use with select/write-select.c.
* Connect only. To show what happens if the remote side starts writing but we
* do not read. Use with select/write-select.c.
*
* Instead of this program you can easily use netcat(1). For example:
* Instead of this program you can easily use BSD (also macOS) netcat(1).
* GNU/Linux netcat does not help us here as it uses -i for writing only.
*
* nc -i 9999 localhost 2222
* nc -i 2 localhost 2222
*
* If the 3rd parameter is used, the program will actually read some data each
* interval. Use that if you only have a GNU netcat.
*
* Note that this program works with IPv4 only which is bad.
*
Expand All @@ -25,13 +29,12 @@
int
main(int argc, char **argv)
{
int fd;
struct sockaddr_in in;
int fd, interval = -1;
struct sockaddr_in in = { 0 };

if (argc != 3)
errx(1, "usage: %s <ip-address> <port>", argv[0]);
if (argc != 3 && argc != 4)
errx(1, "usage: %s <ip-address> <port> [interval]", argv[0]);

bzero(&in, sizeof (in));
in.sin_family = AF_INET;
in.sin_port = htons(atoi(argv[2]));

Expand All @@ -42,17 +45,33 @@ main(int argc, char **argv)
if (inet_pton(AF_INET, argv[1], &(in.sin_addr)) != 1)
errx(1, "inet_pton failed for '%s'", argv[1]);

if (argc == 4)
interval = atoi(argv[3]);

if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
err(1, "socket");

if (connect(fd, (struct sockaddr *) &in, sizeof (in)) == -1)
err(1, "connect");

/* Wait for ever. */
while (1)
pause();
if (interval == -1) {
/* Wait for ever. */
while (1)
pause();
}

while (1) {
int n;
char buf[4096];

/* Not reached. */
sleep(interval);
n = read(fd, buf, sizeof (buf));
if (n == -1)
err(1, "read");
if (n == 0)
break;
(void) write(1, buf, n);
}
close(fd);
return (0);
}
49 changes: 26 additions & 23 deletions select/write-select.c
@@ -1,40 +1,43 @@
/*
* Example on writing data with select(). Use select/connect-only.c which
* connects but does not read anything. Alternatively, you can use netcat with
* -i option:
* connects but does not read anything unless a 3rd parameter is provided.
* Alternatively, you can use BSD (ie. macOS as well) netcat with -i option
* (GNU/Linux netcat uses -i for writing only, not for reading, and is not
* useful in this case):
*
* nc -i 9999 localhost 2222
* nc -i 5 localhost 2222
*
* The program should stop in select() after some data has been written to the
* kernel buffer. That's because only some data has been sent over the TCP
* connection - as the other side does not read, we get TCP win 0 after a short
* while and the kernel buffer is limited in size.
* The process should stop in select() after some data has been sent over to the
* remote side and filled up its kernel buffer for the connection there. As the
* client side does not read (or reads slowly), the server side eventually gets
* a TCP window 0 (which you could see with tcpdump) after a short while as the
* kernel buffer holding the data to be read by the client is limited in size.
*
* You might need to run the client from a different machine; it might not
* behave as expected on a localhost. System can treat that as a special case.
*
* To see more, use "-i 1", and trace system calls (eg. use strace on Linux) by
* the server from another terminal. You will see that from time to time, the
* select() returns and the kernel buffer is filled up while the netcat slowly
* reads the data.
* To see more, use "-i 1" with netcat above, and from another terminal, trace
* system calls (eg. use "strace -p <pid>" on Linux) performed by the server.
* You will see that from time to time, the select() returns and the kernel
* buffer is filled up while the netcat slowly reads the data.
*
* (c) jp@devnull.cz
*/

#define _XOPEN_SOURCE 700

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <netdb.h>
#include <err.h>
#include <fcntl.h>
#include <libgen.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <err.h>
#include <errno.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>

#define BUF_LEN 1024

Expand All @@ -47,7 +50,7 @@ main(int argc, char **argv)
int s, newsock, n, total = 0, optval = 1;

if (argc != 2)
errx(1, "usage: %s <port>", argv[0]);
errx(1, "usage: %s <port>", basename(argv[0]));

if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1)
err(1, "socket");
Expand All @@ -63,7 +66,7 @@ main(int argc, char **argv)
err(1, "setsockopt");
}

if (bind(s, (struct sockaddr *) &sa, sizeof (sa)) == -1)
if (bind(s, (struct sockaddr *)&sa, sizeof (sa)) == -1)
err(1, "bind");

if (listen(s, SOMAXCONN) == -1)
Expand All @@ -73,7 +76,7 @@ main(int argc, char **argv)
err(1, "accept");

/*
* Just write data to the remote side. If the remote side does not read
* Just write data to the remote side. If the remote side does not read
* the data we should be finally put to sleep in select().
*/
for (;;) {
Expand All @@ -85,7 +88,7 @@ main(int argc, char **argv)

if (FD_ISSET(newsock, &wrfds)) {
if ((n = write(newsock, buf, sizeof (buf))) == -1)
err(1, "write (%d)", errno);
err(1, "write");
total = total + n;
fprintf(stderr, "[ %d bytes written (total %d) ]\n",
n, total);
Expand Down

0 comments on commit 8833e60

Please sign in to comment.