-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathudp-client.c
119 lines (107 loc) · 4.2 KB
/
udp-client.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#include <errno.h>
#include <fcntl.h> // for opening socket
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <netdb.h>
#include <unistd.h> // for closing socket
#include <sys/socket.h>
#include <sys/types.h>
#define BUFFER_SIZE 1024
/**
* The entrance of the server application.
*
* @param argc the number of arguments
* @param argv a pointer to a char array that stores arguments
* @return 0 if the application exited normally
*/
int main(int argc, char *argv[]) {
if ( argc != 3 ) {
fprintf(stderr," Usage: %s Host PortNumber\n",argv[0]);
return EXIT_FAILURE;
}
struct hostent* pHost = gethostbyname(argv[1]);
if ( pHost == NULL ) {
fprintf(stderr, "Usage: %s Host PortNumber\n", argv[0]);
return EXIT_FAILURE;
}
int portNumber = atoi(argv[2]);
if ( portNumber <= 0 ) {
fprintf(stderr, "Usage: %s Host PortNumber\n", argv[0]);
return EXIT_FAILURE;
}
/*
* Create socket file descriptor.
* Function Prototype: int socket(int domain, int type,int protocol)
* Defined in sys/socket.h
*
* @param domain: AF_INET stands for Internet, AF_UNIX can only communicate between UNIX systems.
* @param type the prototype to use, SOCK_STREAM stands for udp and SOCK_DGRAM stands for UDP
* @param protocol if type is specified, this parameter can be assigned to 0.
* @return -1 if socket is failed to create
*/
int udpSocketFileDescriptor = socket(AF_INET, SOCK_DGRAM, 0);
if ( udpSocketFileDescriptor == -1 ) {
fprintf(stderr, "[ERROR] Failed to create socket: %s\n", strerror(errno));
return EXIT_FAILURE;
}
/*
* Initialize sockaddr struct.
*
* The structure of sockaddr:
*
* struct sockaddr{
* unisgned short as_family;
* char sa_data[14];
* };
*
* To keep compatibility in different OS, sockaddr_in is used:
*
* struct sockaddr_in{
* unsigned short sin_family; // assigned to AF_INET generally
* unsigned short int sin_port; // the port number listens to
* struct in_addr sin_addr; // assigned to INADDR_ANY for communicating with any hosts
* unsigned char sin_zero[8]; // stuffing bits
* };
*
* Both of them are defined in netinet/in.h
*/
socklen_t sockaddrSize = sizeof(struct sockaddr);
struct sockaddr_in serverSocketAddress;
bzero(&serverSocketAddress, sockaddrSize);
serverSocketAddress.sin_family = AF_INET;
serverSocketAddress.sin_addr=*((struct in_addr *)pHost->h_addr);
serverSocketAddress.sin_port = htons(portNumber);
char inputBuffer[BUFFER_SIZE] = {0};
char outputBuffer[BUFFER_SIZE] = {0};
fprintf(stderr, "[INFO] Congratulations! Connection established with server.\nType \'BYE\' to disconnect.\n");
do {
// Send a message to client
fprintf(stderr, "> ");
fgets(outputBuffer, BUFFER_SIZE, stdin);
// Remove \n character at the end of the string
outputBuffer[strlen(outputBuffer) - 1] = 0;
if ( sendto(udpSocketFileDescriptor, outputBuffer, strlen(outputBuffer) + 1,
0, (struct sockaddr *)(&serverSocketAddress), sockaddrSize) == -1 ) {
fprintf(stderr, "[ERROR] An error occurred while sending message to the server: %s\nThe connection is going to close.\n", strerror(errno));
break;
}
// Stop sending message to server
if ( strcmp("BYE", outputBuffer) == 0 ) {
break;
}
// Receive a message from client
int readBytes = recvfrom(udpSocketFileDescriptor, inputBuffer, BUFFER_SIZE,
0, (struct sockaddr *)(&serverSocketAddress), &sockaddrSize);
if ( readBytes < 0 ) {
fprintf(stderr, "[ERROR] An error occurred while receiving message from the server: %s\nThe connection is going to close.\n", strerror(errno));
break;
}
fprintf(stderr, "[INFO] Received a message from server: %s\n", inputBuffer);
} while ( 1 );
/*
* Close socket for client.
*/
close(udpSocketFileDescriptor);
return EXIT_SUCCESS;
}