-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathserver.c
138 lines (103 loc) · 5.06 KB
/
server.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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/*
NOTES :
Stages for server
Socket creation:
int sockfd = socket(domain, type, protocol)
sockfd: socket descriptor, an integer (like a file-handle)
domain: integer, communication domain e.g., AF_INET (IPv4 protocol) , AF_INET6 (IPv6 protocol)
type: communication type
SOCK_STREAM: TCP(reliable, connection oriented)
SOCK_DGRAM: UDP(unreliable, connectionless)
protocol: Protocol value for Internet Protocol(IP), which is 0. This is the same number which appears on protocol field in the IP header of a packet.(man protocols for more details)
Setsockopt:
int setsockopt(int sockfd, int level, int optname,
const void *optval, socklen_t optlen);
This helps in manipulating options for the socket referred by the file descriptor sockfd. This is completely optional, but it helps in reuse of address and port. Prevents error such as: “address already in use”.
Bind:
int bind(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
After creation of the socket, bind function binds the socket to the address and port number specified in addr(custom data structure). In the example code, we bind the server to the localhost, hence we use INADDR_ANY to specify the IP address.
Listen:
int listen(int sockfd, int backlog);
It puts the server socket in a passive mode, where it waits for the client to approach the server to make a connection. The backlog, defines the maximum length to which the queue of pending connections for sockfd may grow. If a connection request arrives when the queue is full, the client may receive an error with an indication of ECONNREFUSED.
Accept:
int new_socket= accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
It extracts the first connection request on the queue of pending connections for the listening socket, sockfd, creates a new connected socket, and returns a new file descriptor referring to that socket. At this point, connection is established between client and server, and they are ready to transfer data.
struct sockaddr {
ushort sa_family;
char sa_data[14];
};
struct sockaddr_in{
short sin_family;
unsigned short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
Parameters :
sin_family
Address family (must be AF_INET).
sin_port
IP port.
sin_addr
IP address.
sin_zero
Padding to make structure the same size as SOCKADDR.
This is the form of the SOCKADDR structure specific to the Internet address family and can be cast to SOCKADDR.
The IP address component of this structure is of type IN_ADDR. The IN_ADDR structure is defined in Windows Sockets header file WINSOCK.H
*/
#include <stdio.h>
#include <unistd.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
void error(char* msg){
perror(msg);
exit(1);
}
int main(int argc, char *argv[]){
if(argc<2){
fprintf(stderr,"No port provided\n");
exit(1);
}
int sockfd, newsockfd, portno, n; //File descriptor for Sockets
char buffer[255]; //Temporary buffer to read and write data
struct sockaddr_in serv_addr,cli_addr; //Structure to hold Server and Client details
socklen_t cli_len; //Client length
sockfd = socket(AF_INET, SOCK_STREAM, 0); //AF_INET refers to addresses from the internet, IP addresses specifically. SOCK_STREAM to refer TCP(SOCK_DGRAM for UDP), 0 again for TCP
if(sockfd<0){
error("Socket failed \n");
}
bzero((char*) &serv_addr,sizeof(serv_addr)); //The bzero() function shall place n zero-valued bytes in the area pointed to by s.
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY; //INADDR_ANY is used when you don't need to bind a socket to a specific IP. When you use this value as the address when calling bind() , the socket accepts connections to all the IPs of the machine.
serv_addr.sin_port = htons(portno); //the htons() function converts values between host and network byte orders. There is a difference between big-endian and little-endian and network byte order depending on your machine and network protocol in use.
if(bind(sockfd, (struct sockaddr*) &serv_addr,sizeof(serv_addr))<0){ //Binding the socket
error("Binding failed\n");
}
listen(sockfd, 5);//Listening for new Connections
cli_len = sizeof(cli_addr);
newsockfd = accept(sockfd, (struct sockaddr*) &cli_addr, &cli_len);//Accept the new connection
if(newsockfd<0)
error("error accepting new connection \n");
while(1){
bzero(buffer, 256);
n = read(newsockfd, buffer, 255); //Read incoming data streams
if(n<0)
error("Error reading from Client");
printf("Client : %s \n", buffer);
bzero(buffer, 255);
printf("Server :");
fgets(buffer, 255, stdin);
n = write(newsockfd, buffer, strlen(buffer));
if(n<0)
error("Error writing to server\n");
if(strncmp(buffer, "Bye", 3) == 0)
break;
}
close(sockfd);
close(newsockfd);
return 0;
}