|
| 1 | +#include <sys/socket.h> |
| 2 | +#include <sys/types.h> |
| 3 | +#include <netdb.h> |
| 4 | +#include <netinet/in.h> |
| 5 | +#include <stdio.h> |
| 6 | +#include <stdlib.h> |
| 7 | +#include <string.h> |
| 8 | +#include <arpa/inet.h> |
| 9 | +#include <pthread.h> |
| 10 | +#include <unistd.h> |
| 11 | + |
| 12 | +#define PORT 10609 |
| 13 | +#define SIZE 1000 |
| 14 | + |
| 15 | +typedef struct |
| 16 | +{ |
| 17 | + unsigned int length; |
| 18 | + unsigned char data[SIZE]; |
| 19 | +} Message; |
| 20 | + |
| 21 | +typedef enum |
| 22 | +{ |
| 23 | + Ok, // operation successful |
| 24 | + Bad, // unrecoverable error |
| 25 | + Wronglength // bad message length supplied |
| 26 | +}Status; |
| 27 | + |
| 28 | +typedef struct sockaddr_in SocketAddress; |
| 29 | + |
| 30 | + |
| 31 | +struct hostent *gethostbyname() ; |
| 32 | +void makeDestSA(SocketAddress * sa, char *hostname, int port) ; |
| 33 | +void printSA(SocketAddress sa); |
| 34 | +void makeLocalSA(SocketAddress *sa) ; |
| 35 | +void makeDestSA(SocketAddress * sa, char *hostname, int port); |
| 36 | +Status anyThingThere(int s); |
| 37 | +Status UDPsend(int s, Message *m, SocketAddress destination); |
| 38 | +Status UDPreceive(int s, Message *m, SocketAddress *origin); |
| 39 | +Status DoOperation (Message *message, Message *reply, int s, SocketAddress serverSA); |
| 40 | + |
| 41 | + |
| 42 | +void main(int argc, char **argv) |
| 43 | +{ |
| 44 | + //Server's host name must be entered as an argument else the program exits |
| 45 | + if(argv[1] == NULL){ |
| 46 | + printf("Server host name not entered..exiting\n"); |
| 47 | + exit(1); |
| 48 | + } |
| 49 | + |
| 50 | + int s, port=PORT, n=0; |
| 51 | + Message message1, message2; |
| 52 | + SocketAddress mySocketAddress, yourSocketAddress; |
| 53 | + memset(&message1, 0, sizeof(message1)); |
| 54 | + |
| 55 | + //Create a socket, if failed to, exit from the program |
| 56 | + if(( s = socket(AF_INET, SOCK_DGRAM, 0))<0) { |
| 57 | + perror("socket failed"); |
| 58 | + return; |
| 59 | + } |
| 60 | + |
| 61 | + //call makeLocalSA to make a socket address using any of the addressses of this computer for a local socket on any port |
| 62 | + makeLocalSA(&mySocketAddress); |
| 63 | + |
| 64 | + //Bind to the local port, if failes to, close the socket and then return |
| 65 | + if( bind(s, (struct sockaddr *)&mySocketAddress, sizeof(struct sockaddr_in))!= 0){ |
| 66 | + perror("Bind failed\n"); |
| 67 | + close (s); |
| 68 | + return; |
| 69 | + } |
| 70 | + |
| 71 | + //prints socket address |
| 72 | + |
| 73 | + printSA(mySocketAddress); |
| 74 | + makeDestSA(&yourSocketAddress, argv[1], port); |
| 75 | + |
| 76 | + while(1) |
| 77 | + { |
| 78 | + printf("Enter the message to be sent to server\n"); |
| 79 | + |
| 80 | + //Reads the message from user |
| 81 | + fgets(message1.data, SIZE, stdin); |
| 82 | + char *pos; |
| 83 | + if((pos=strchr(message1.data, '\n')) != NULL) |
| 84 | + { |
| 85 | + //If the message does not have null in the end, adds null |
| 86 | + *pos = '\0'; |
| 87 | + } |
| 88 | + else |
| 89 | + { |
| 90 | + printf("Input too long for buffer\n"); |
| 91 | + exit(1); |
| 92 | + } |
| 93 | + message1.length=strnlen(message1.data, SIZE); |
| 94 | + |
| 95 | + //call DoOperation function: sends message to the server and waits till a reply is received from the server |
| 96 | + DoOperation(&message1, &message2, s, yourSocketAddress); |
| 97 | + |
| 98 | + //client waits for 2 seconds before sending next message: sends peridic requests |
| 99 | + sleep(2); |
| 100 | + } |
| 101 | +} |
| 102 | + |
| 103 | + |
| 104 | +/*sends a given request message to a given socket address and blocks until it returns with a reply message and returns status*/ |
| 105 | +Status DoOperation (Message *message, Message *reply, int s, SocketAddress serverSA) |
| 106 | +{ |
| 107 | + Status status=Ok; |
| 108 | + int n=0; |
| 109 | + SocketAddress receiveSA; |
| 110 | + memset(&receiveSA, 0, sizeof(receiveSA)); |
| 111 | + socklen_t addrlen = sizeof(receiveSA); |
| 112 | + |
| 113 | + //if status returned by UDPsend is Ok, continue to wait for receive else set the status to bad |
| 114 | + if( (status=UDPsend(s, message, serverSA)) ==Ok) |
| 115 | + { |
| 116 | + printf("Message sent ..waiting for the server to reply\n"); |
| 117 | + } |
| 118 | + else |
| 119 | + { |
| 120 | + status=Bad; |
| 121 | + printf("Could not send the message from client, status Bad\n"); |
| 122 | + } |
| 123 | + if(status==Ok) |
| 124 | + { |
| 125 | + int i=1; |
| 126 | + while(i<4) |
| 127 | + { |
| 128 | + if(anyThingThere(s)==Bad) |
| 129 | + { |
| 130 | + //no available socket fd, status bad, send message again |
| 131 | + status=Bad; |
| 132 | + printf("Sending message again\n"); |
| 133 | + UDPsend(s, message, serverSA); |
| 134 | + } |
| 135 | + else |
| 136 | + { |
| 137 | + status=Ok; |
| 138 | + //socket fd available, receives the message from server |
| 139 | + if((status= UDPreceive(s, reply, &serverSA)) == Ok) |
| 140 | + { |
| 141 | + printf("Message received from server: %s\n", reply->data); |
| 142 | + } |
| 143 | + else |
| 144 | + { |
| 145 | + printf("No message received from server\n"); |
| 146 | + status=Bad; |
| 147 | + } |
| 148 | + break; |
| 149 | + } |
| 150 | + i++; |
| 151 | + } |
| 152 | + |
| 153 | + } |
| 154 | + if(status==Bad) // socket fd not available after checking 3 times also. Client program displays message and exits |
| 155 | + { |
| 156 | + printf("Timeout, no response from server. Exiting client..\n"); |
| 157 | + exit(1); |
| 158 | + } return status; |
| 159 | +} |
| 160 | + |
| 161 | + |
| 162 | +// use select to test whether there is any input on descriptor |
| 163 | +Status anyThingThere(int s) |
| 164 | +{ |
| 165 | + Status timeoutstatus=Ok; |
| 166 | + fd_set rfds; |
| 167 | + struct timeval timeout; |
| 168 | + int n; |
| 169 | + FD_ZERO(&rfds); |
| 170 | + FD_SET(s, &rfds); |
| 171 | + timeout.tv_sec =3; /*seconds wait*/ |
| 172 | + timeout.tv_usec = 0; /* micro seconds*/ |
| 173 | + if((n = select(s+1, &rfds, 0, 0, &timeout))<0) |
| 174 | + perror("Select fail:\n"); |
| 175 | + else if(!n) |
| 176 | + { |
| 177 | + timeoutstatus=Bad; |
| 178 | + } |
| 179 | + return timeoutstatus; |
| 180 | +} |
| 181 | + |
| 182 | +/* sends a given message through a socket to a given socket address and returns status*/ |
| 183 | +Status UDPsend(int s, Message *m, SocketAddress destination) |
| 184 | +{ |
| 185 | + Status status;int n; |
| 186 | + if( (n = sendto(s, m, sizeof(Message), 0, (struct sockaddr *)&destination, sizeof(destination))) > 0) |
| 187 | + { |
| 188 | + status=Ok; |
| 189 | + } |
| 190 | + else |
| 191 | + { |
| 192 | + |
| 193 | + printf("UDPsend: Could not send reply back to client, Status is bad\n"); |
| 194 | + status=Bad; |
| 195 | + } |
| 196 | + return status; |
| 197 | +} |
| 198 | + |
| 199 | +/*receives a message and the socket address of the sender and returns status*/ |
| 200 | +Status UDPreceive(int s, Message *m, SocketAddress *origin) |
| 201 | +{ |
| 202 | + Status status; |
| 203 | + int addrlen=sizeof(SocketAddress); |
| 204 | + int n=0; |
| 205 | + if((n = recvfrom(s, m, sizeof(Message), 0, (struct sockaddr *)origin, &addrlen)) > 0) |
| 206 | + { |
| 207 | + status=Ok; |
| 208 | + } |
| 209 | + else |
| 210 | + { |
| 211 | + printf("UDP Receive: Status is bad\n"); |
| 212 | + status=Bad; |
| 213 | + } |
| 214 | + return status; |
| 215 | +} |
| 216 | + |
| 217 | + |
| 218 | + |
| 219 | +/* make a socket address using any of the addressses of this computer |
| 220 | +for a local socket on any port */ |
| 221 | +void makeLocalSA(SocketAddress *sa) |
| 222 | +{ |
| 223 | + sa->sin_family = AF_INET; |
| 224 | + sa->sin_port = htons(0); |
| 225 | + sa-> sin_addr.s_addr = htonl(INADDR_ANY); |
| 226 | +} |
| 227 | + |
| 228 | + |
| 229 | +/*print a socket address */ |
| 230 | +void printSA(SocketAddress sa) |
| 231 | +{ |
| 232 | + char mybuf[80]; |
| 233 | + inet_ntop(AF_INET, &sa.sin_addr, mybuf, 80); |
| 234 | + printf("sa = %d, %s, %d\n", sa.sin_family, mybuf, ntohs(sa.sin_port)); |
| 235 | +} |
| 236 | + |
| 237 | + |
| 238 | +/* make a socket address for a destination whose machine and port are given as arguments */ |
| 239 | +void makeDestSA(SocketAddress * sa, char *hostname, int port) |
| 240 | +{ |
| 241 | + struct hostent *host; |
| 242 | + |
| 243 | + sa->sin_family = AF_INET; |
| 244 | + if((host = gethostbyname(hostname))== NULL){ |
| 245 | + printf("Unknown host name\n"); |
| 246 | + exit(-1); |
| 247 | + } |
| 248 | + sa-> sin_addr = *(struct in_addr *) (host->h_addr); |
| 249 | + sa->sin_port = htons(port); |
| 250 | +} |
| 251 | + |
| 252 | + |
| 253 | + |
0 commit comments