sock_client.c (4454B)
1 #include <sys/socket.h> 2 #include <sys/types.h> 3 4 #include <arpa/inet.h> 5 #include <netdb.h> 6 #include <netinet/in.h> 7 8 #include <err.h> 9 #include <libgen.h> 10 #include <stdarg.h> 11 #include <stdio.h> 12 #include <stdlib.h> 13 #include <string.h> 14 #include <unistd.h> 15 16 static void esend(int, void *, size_t, int); 17 static void erecv(int, void *, size_t, int); 18 static void *emalloc(size_t); 19 static void safe_scanf(void *, char *, char *, ...); 20 static void calc_avg(int); 21 static void calc_minmax(int); 22 static void calc_prod(int); 23 static void usage(void); 24 25 static char *argv0; 26 27 /* 28 * Error checking send(2). 29 */ 30 static void 31 esend(int fd, void *msg, size_t len, int flags) 32 { 33 if (send(fd, msg, len, flags) < 0) 34 err(1, "send"); 35 } 36 37 /* 38 * Error checking recv(2). 39 */ 40 static void 41 erecv(int fd, void *msg, size_t len, int flags) 42 { 43 if (recv(fd, msg, len, flags) < 0) 44 err(1, "recv"); 45 } 46 47 /* 48 * Error checking malloc(3). 49 */ 50 static void * 51 emalloc(size_t nb) 52 { 53 void *p; 54 55 if ((p = malloc(nb)) == NULL) 56 err(1, "malloc"); 57 return (p); 58 } 59 60 /* 61 * The server might break if we give it incorrent input, so we have to make 62 * sure we'll always read proper input from scanf() before we send it to the 63 * server. 64 */ 65 static void 66 safe_scanf(void *n, char *type, char *fmt, ...) 67 { 68 va_list ap; 69 char buf[BUFSIZ]; 70 int rc; 71 72 do { 73 va_start(ap, fmt); 74 vsprintf(buf, fmt, ap); 75 va_end(ap); 76 printf("\r%s", buf); 77 rc = scanf(type, n); 78 (void)getchar(); 79 } while (rc != 1); 80 } 81 82 static void 83 calc_avg(int fd) 84 { 85 float res; 86 int *arr, n, i; 87 88 safe_scanf(&n, "%d", "%s> n: ", argv0); 89 arr = emalloc(n * sizeof(int)); 90 for (i = 0; i < n; i++) 91 safe_scanf(&arr[i], "%d", "%s> arr[%d]: ", argv0, i); 92 93 esend(fd, &n, sizeof(int), 0); 94 esend(fd, arr, n * sizeof(int), 0); 95 96 erecv(fd, &res, sizeof(float), 0); 97 printf("[%s] server response: %.3f\n", argv0, res); 98 99 free(arr); 100 } 101 102 static void 103 calc_minmax(int fd) 104 { 105 int res[2], *arr, n, i; 106 107 safe_scanf(&n, "%d", "%s> n: ", argv0); 108 arr = emalloc(n * sizeof(int)); 109 for (i = 0; i < n; i++) 110 safe_scanf(&arr[i], "%d", "%s> arr[%d]: ", argv0, i); 111 112 esend(fd, &n, sizeof(int), 0); 113 esend(fd, arr, n * sizeof(int), 0); 114 115 erecv(fd, &res, 2 * sizeof(int), 0); 116 printf("[%s] server response: min: %d, max: %d\n", 117 argv0, res[0], res[1]); 118 119 free(arr); 120 } 121 122 static void 123 calc_prod(int fd) 124 { 125 float *res, a; 126 int *arr, n, i; 127 128 safe_scanf(&a, "%f", "%s> a: ", argv0); 129 safe_scanf(&n, "%d", "%s> n: ", argv0); 130 arr = emalloc(n * sizeof(int)); 131 for (i = 0; i < n; i++) 132 safe_scanf(&arr[i], "%d", "%s> arr[%d]: ", argv0, i); 133 134 esend(fd, &a, sizeof(float), 0); 135 esend(fd, &n, sizeof(int), 0); 136 esend(fd, arr, n * sizeof(int), 0); 137 138 res = emalloc(n * sizeof(float)); 139 erecv(fd, res, n * sizeof(float), 0); 140 printf("[%s] server response: [", argv0); 141 for (i = 0; i < n; i++) 142 printf("%.3f%s", res[i], i == n - 1 ? "" : ", "); 143 printf("]\n"); 144 145 free(arr); 146 free(res); 147 } 148 149 static void 150 usage(void) 151 { 152 fprintf(stderr, "usage: %s [-p port] hostname\n", argv0); 153 exit(0); 154 } 155 156 int 157 main(int argc, char *argv[]) 158 { 159 struct sockaddr_in sin; 160 struct hostent *hp; 161 int port = 9999; 162 int fd, n; 163 char *host, ch; 164 165 argv0 = basename(*argv); 166 while ((ch = getopt(argc, argv, "p:")) != -1) { 167 switch (ch) { 168 case 'p': 169 if ((port = atoi(optarg)) < 1024) 170 errx(1, "can't use port number < 1024"); 171 break; 172 case '?': 173 default: 174 usage(); 175 } 176 } 177 argc -= optind; 178 argv += optind; 179 180 if (argc < 1) 181 usage(); 182 host = *argv; 183 184 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) 185 err(1, "socket(AF_INET)"); 186 memset(&sin, 0, sizeof(sin)); 187 sin.sin_family = AF_INET; 188 sin.sin_port = htons(port); 189 if (!inet_aton(host, &sin.sin_addr)) { 190 if ((hp = gethostbyname(host)) == NULL) 191 errx(1, "gethostbyname(%s) failed", host); 192 (void)memcpy(&sin.sin_addr, hp->h_addr, hp->h_length); 193 } 194 if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) 195 err(1, "connect"); 196 197 for (;;) { 198 printf("1: average\n2: min and max\n3: product\n4: disconnect\n"); 199 safe_scanf(&n, "%d", "%s> your choice: ", argv0); 200 201 switch (n) { 202 case 1: 203 /* 204 * Send our choice to the server so that it can read at 205 * the appropriate RPC. 206 */ 207 esend(fd, &n, sizeof(int), 0); 208 calc_avg(fd); 209 break; 210 case 2: 211 esend(fd, &n, sizeof(int), 0); 212 calc_minmax(fd); 213 break; 214 case 3: 215 esend(fd, &n, sizeof(int), 0); 216 calc_prod(fd); 217 break; 218 case 4: 219 esend(fd, &n, sizeof(int), 0); 220 goto end; 221 default: 222 printf("[%s] invalid choice\n", argv0); 223 } 224 } 225 end: 226 close(fd); 227 228 return (0); 229 }