description |
---|
05/31/2022 |
Socket programming is a way of connecting two or more nodes on a network in order to communicate with one another. This can be used for both legitimate and malcious purposes.
This system follows what is known as a client/server model.
Sockets are low level endpoints used for processing information across a network.
- Socket Creation
int sockfd = socket(domain, type, protocol)
sockfd
: socket descriptor, an integer- domain: integer, specifies communication domain. We can use
AF_LOCAL
as defined in the POSIX standard for communication between processes on the same host. For communicating on different hosts connected by IPv4, you will want to useAF_INET
andAF_INET 6
for processes connected via IPv6 - type: communication type
- protocol: Protocol value for IP, which is 0
- This will appear as a number on protocol field in the IP header of a packet (run man protocols for more info)
- Setsockopt
This helps in manipulating options for the socket referred by the file descriptor sockfd. This is completely optional.
However, it helps with reuse of address and port. It prevents the error such as: "Address already in use".
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
NOTE: setsockopt
is only found in server socket code.
- Bind
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
After the creation of the socket, the bind function will then bind the socket to the address and port number specified in addr (custom data structure).
- Listen
int listen(int sockfd, int backlog);
This will put the server socket in a passive mode, where it will wait for the client to make a connection to the server.
Here exists what is known as the backlog, which defines the maximum length of a queue for pending connection for sockfd to grow.
If a client request arrives and the queue is full, the client may receive an error that indicates 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 for that socket.
This is where the connection is granted life and has been established.
A connection has now been established between client and server and are therefore ready to transfer data.
- Socket Connection
This works exactly the same as Socket Creation for the Server Process.
Please refer to step 1 above for more information/clarity.
- Connect
The connect() system call connects the socket referred to by the file descriptor sockfd
to the address specified by addr
. Server's address and port is specified in addr
.
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#define PORT 1337
int main(int argc, char const* argv[])
{
int server_fd, new_socket, valread;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
char buffer[1024] = { 0 };
char* hello = "Hello from server";
// Creating socket file descriptor
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}
// Forcefully attaching socket to the port 8080
if (setsockopt(server_fd, SOL_SOCKET,
SO_REUSEADDR | SO_REUSEPORT, &opt,
sizeof(opt))) {
perror("setsockopt");
exit(EXIT_FAILURE);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(PORT);
// Forcefully attaching socket to the port 8080
if (bind(server_fd, (struct sockaddr*)&address,
sizeof(address))
< 0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
if (listen(server_fd, 3) < 0) {
perror("listen");
exit(EXIT_FAILURE);
}
if ((new_socket
= accept(server_fd, (struct sockaddr*)&address,
(socklen_t*)&addrlen))
< 0) {
perror("accept");
exit(EXIT_FAILURE);
}
valread = read(new_socket, buffer, 1024);
printf("%s\n", buffer);
send(new_socket, hello, strlen(hello), 0);
printf("Hello message sent\n");
// closing the connected socket
close(new_socket);
// closing the listening socket
shutdown(server_fd, SHUT_RDWR);
return 0;
}
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#define PORT 1337
int main(int argc, char const* argv[])
{
int status, valread, client_fd;
struct sockaddr_in serv_addr;
char* hello = "Hello from client";
char buffer[1024] = { 0 };
if ((client_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("\n Socket creation error \n");
return -1;
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
// Convert IPv4 and IPv6 addresses from text to binary
// form
if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr)
<= 0) {
printf(
"\nInvalid address/ Address not supported \n");
return -1;
}
if ((status
= connect(client_fd, (struct sockaddr*)&serv_addr,
sizeof(serv_addr)))
< 0) {
printf("\nConnection Failed \n");
return -1;
}
send(client_fd, hello, strlen(hello), 0);
printf("Hello message sent\n");
valread = read(client_fd, buffer, 1024);
printf("%s\n", buffer);
// closing the connected socket
close(client_fd);
return 0;
}