source: benchmark/io/sendfile/consumer.c @ 6009a5a

Last change on this file since 6009a5a was 6dc17a3d, checked in by Thierry Delisle <tdelisle@…>, 3 years ago

Changed consumer to run for ever.

  • Property mode set to 100644
File size: 3.6 KB
Line 
1// Simple sink program that opens a tcp socket on a random port
2// and then reads everything the socket has to write and then ends.
3
4#define _GNU_SOURCE
5
6#include <stdint.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10
11#include <errno.h>
12#include <time.h>
13#include <unistd.h>
14
15#include <sys/socket.h>
16#include <netinet/in.h>
17
18enum {
19        USAGE_ERROR = 1,
20        SOCKET_ERROR,
21        BIND_INUSE,
22        BIND_ERROR,
23        GETNAME_ERROR,
24        LISTEN_ERROR,
25        ACCEPT_ERROR,
26        READ_ERROR
27};
28
29enum { buffer_len = 10240 };
30char buffer[buffer_len];
31
32enum { TIMEGRAN = 1000000000LL };
33
34int main(int argc, char * argv[]) {
35        int port = 0;
36        switch(argc) {
37        case 1: break;
38        case 2:
39                {
40                        const char * const str = argv[1];
41                        char* endptr;
42                        unsigned long long ret = strtoul(str, &endptr, 10);
43                        if('\0' != *endptr) { fprintf( stderr, "Invalid argument \"%s\" (not a number)\n", str ); goto USAGE;}
44                        if(errno == ERANGE || ret > 65535)  { fprintf( stderr, "Invalid argument \"%s\" (value too large)\n", str ); goto USAGE;}
45
46                        port = ret;
47                        break;
48                }
49        USAGE:
50        default:
51                fprintf( stderr, "USAGE: %s [port]\n", argv[0] );
52                exit( USAGE_ERROR );
53        }
54
55        printf( "%d: Listening on port %d\n", getpid(), port );
56        int listenfd = socket(AF_INET, SOCK_STREAM, 0);
57        if(listenfd < 0) {
58                fprintf( stderr, "socket error: (%d) %s\n", (int)errno, strerror(errno) );
59                exit( SOCKET_ERROR );
60        }
61
62        int ret = 0;
63        struct sockaddr_in address;
64        socklen_t addrlen = sizeof(address);
65        memset( (char *)&address, '\0', addrlen );
66        address.sin_family = AF_INET;
67        address.sin_addr.s_addr = htonl( INADDR_ANY );
68        address.sin_port = htons( port );
69
70        ret = bind( listenfd, (struct sockaddr *) &address, addrlen );
71        if(ret < 0) {
72                if(errno == EADDRINUSE) {
73                        fprintf( stderr, "Port already in use in non-interactive mode. Aborting\n" );
74                        exit( BIND_INUSE );
75                }
76                fprintf( stderr, "bind error: (%d) %s\n", (int)errno, strerror(errno) );
77                exit( BIND_ERROR );
78        }
79
80        ret = getsockname( listenfd, (struct sockaddr *) &address, &addrlen );
81        if(ret < 0) {
82                fprintf( stderr, "getname error: (%d) %s\n", (int)errno, strerror(errno) );
83                exit(GETNAME_ERROR);
84        }
85
86        printf( "actial port: %d\n", ntohs(address.sin_port) );
87
88        ret = listen( listenfd, 1 );
89        if(ret < 0) {
90                fprintf( stderr, "listen error: (%d) %s\n", (int)errno, strerror(errno) );
91                exit( 5 );
92        }
93
94        for(;;) {
95                struct sockaddr_in cli_addr;
96                __socklen_t clilen = sizeof(cli_addr);
97                int fd = accept( listenfd, (struct sockaddr *) &cli_addr, &clilen );
98                if(fd < 0) {
99                        fprintf( stderr, "accept error: (%d) %s\n", (int)errno, strerror(errno) );
100                        exit( ACCEPT_ERROR );
101                }
102
103                int error = 0;
104                size_t calls = 0;
105                size_t bytes = 0;
106
107                struct timespec after, before;
108
109                clock_gettime(CLOCK_MONOTONIC, &before);
110
111                for(;;) {
112                        ret = recv(fd, buffer, buffer_len, 0);
113                        if(ret == 0 ) goto EXIT;
114                        if(ret < 0 ) {
115                                if( errno == EAGAIN || errno == EWOULDBLOCK) continue;
116                                if( errno == ECONNRESET ) { printf("Connection reset\n"); goto EXIT; }
117                                if( errno == EPIPE ) { printf("Pipe closed\n"); goto EXIT; }
118                                fprintf( stderr, "accept error: (%d) %s\n", (int)errno, strerror(errno) );
119                                error = READ_ERROR;
120                                goto EXIT;
121                        }
122                        calls++;
123                        bytes += ret;
124                }
125                EXIT:;
126
127                clock_gettime(CLOCK_MONOTONIC, &after);
128
129                uint64_t tb = ((int64_t)before.tv_sec * TIMEGRAN) + before.tv_nsec;
130                uint64_t ta = ((int64_t)after.tv_sec * TIMEGRAN) + after.tv_nsec;
131                double secs = ((double)ta - tb) / TIMEGRAN;
132
133                printf("Received %'zu bytes in %'zu reads, %f seconds\n", bytes, calls, secs);
134                printf(" - %'3.3f bytes per second\n", (((double)bytes) / secs));
135                printf(" - %'3.3f bytes per calls\n", (((double)bytes) / calls));
136
137                close(fd);
138                if(error != 0) exit( error );
139        }
140        close(listenfd);
141        return 0;
142}
Note: See TracBrowser for help on using the repository browser.