Socket Address Structure
struct sockaddr {
unsighed short sa_family;
char sa_data[14];
}
struct sockaddr_in {
short sin_family;
unsigned short sin_port; // Port Number
struct in_addr sin_addr; // IP Address
char sin_zero[8];
}
struct in_addr {
unsighed long s_addr; // 4 bytes long
}
Byte Ordering; Big Endian and Little Endian
Each address stores one element of the memory "array". Each element is typically one byte. So it is commonly called byte-addressable. A word means 32 bits data. We can split this into 4 bytes and each byte goes into the one sell of memory. Depending on which direction each byte goes into the memory, there are Big Endian and Little Endian.
Utility Functions
Convert values between host and network byte order:
htons() - short for host to network short
htonl() - short for host to network long
ntohs() - short for network to host short
ntohl() - short for network to host long
Convert IP address format:
inet_aton() - Ascii dotted to binary
inet_ntoa() - Binary to Ascii dotted
syscalls(); library
Socket() - A Connection Endpoint
This creates an endpoint for a network connection
int Socket(int doman, int type, int protocol);
- domain = PF_INET; For IPv4 communication, domain is always
- type = SOCK_STREAM(TCP), SOCK_DGRAM(UDP)
- protocol = 0 (for simplicity)
/*
* This will create a TCP socket
* It returns a socket descriptor on success and -1 on an error
*/
socket(PF_INET, SOCK_STREAM, 0);
Bind() - Attaching an IP and Port(My Network) to a Socket
A server process calls bind to attach itself to a specific port and IP address
int Bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen)
- sockfd = socket descriptor returned by socket()
- my_addr = pointer to a valid sockaddr_in structure cast as a sockadd * pointer
- addrlen = lenghth of the sockaddr_in structure
struct sockaddr_in my;
my.sin_family = PF_INET;
my.sin_port = htons(80);
my.sin_add.s_addr = INADDR_ANY;
bzero(&my, 8);
bind(sock, (struct sockaddr *)&my, sizeof(,my));
Listen() - Wait for a Connection
The server process calls listen to tell the kernel to initialize a wait queue of connections for this socket
int Listen(int sock, int backlog);
- sock = socket returned by socket()
- backlog = maximum length of the pending connections queue
// This will allow a maximum of 10 connections to be in pending state
Listen(sock, 10);
Accept() - A New Connection
Accept is called by a Server process to accept new connections from new clients trying to connect to the server
int Accept(int socket, (struct sockaddr *)&client, socklen_t *client_len);
- socket = the socket in listen state
- client = will hold the new client's information when accept returns
- client_len = pointer to size of the client structure
struct sockaddr_in client;
int len = sizeof(client);
Accept(sock, (struct sockaddr *)&client, &len); // empty client struct
Connect() - Connect to a Service
Connect is called by a client to connect to a server port
int Connect(int sock, (struct sockaddr *)&server_addr, socklen_t len);
- sock = a socket returned by socket()
- server_addr = a sockaddr_in struct pointer filled with all the remote server details and cast as a sockaddr struct pointer
- len = size of the server_addr struct
connect(sock, (struct sockaddr *)server_addr, len);
Send / Recv - Data
Send(), Recv(), Read(), Write() etc calls are used to send and receive data. The return value is the number of bytes actually sent/received.
int send(int sock, void *mesg, size_t len, int flags);
int recv(int sock, void *mesg, size_t len, int flags);
- sock = a connected socket
- mesg = pointer to a buffer to send/receive data from/in
- len = size of the message buffer
- flags = 0 for simplicity
char send_buffer[1024];
char recv_buffer[1024];
int sent_bytes;
int recvd_bytes;
sent_bytes = send(sock, send_buffer, 1024, 0);
recvd_bytes = recv(sock, recv_buffer, 1024, 0);
Close()
int close(int sock);
close(sock);
Server
TCP Server Using Sockets
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h> // socket
#include <sys/socket.h> // socket
#include <netinet/in.h> // structure
#include <errno.h> // perror
#include <string.h>
int main()
{
int socket, cli;
struct sockaddr_in server, client;
unsigned int len; // len should be a positive num
char mesg[] = "Hello to the world of socket programming!";
int sent;
if((sock = socket(AF_INET, SOCK_STREAN, 0)) == -1)
{
perror("socket: ");
exit(-1);
}
server.sin_family = AF_INET;
server.sin_port = htons(10000);
server.sin_addr.s_addr = INADDR_ANY;
bzero(&server.sin_zero, 8); // bzero sets all values in a buffer zero
len = sizeof(struct sockaddr_in);
if((bind(sock, (struct sockaddr *)&server, len)) == -1)
{
perror("bind");
exit(-1);
}
if ((listen(sock, 5)) == -1)
{
perror("listen");
exit(-1);
}
while(true)
{
// return a client socket descriptor or -1
if ((cli == accept(sock, (struct sockaddr *)&client, &len)) == -1)
{
perror("accept");
exit(-1);
}
sent = send(cli, mesg, strlen(mesg), 0);
// inet_aton() - Ascii dotted to binary
printf("Sent %d bytes to client : %s\n", sent, inet_ntoa(client.sin_addr));
close(cli); // server closes the client server
}
}
Terminal Command
This will check servers that are running
netstat -atp
Connect server with the port number
telnet localhost 10000
TCP Echo Server Using Sockets
/*
* Listening on the port number and waiting for a client to connect
* Once the connection has been established, the client sends messages
* The server receives it and sends it back to the client
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h> // socket
#include <sys/socket.h> // socket
#include <netinet/in.h> // structure
#include <errno.h> // perror
#include <string.h>
#include <unistd.h> // sleep
#include <arpa/inet.h> // inet_addr
#define ERROR -1
#define MAX_CLIENTS 2
#define MAX_DATA 1024
int main(int argc, char **argv)
{
struct sockaddr_in server;
struct sockaddr_in client;
int sock; // server's socket descriptor
int new; // client's socket descriptor
int socketaddr_len = sizeof(struct sockaddr_in);
int data_len;
char data[MAX_DATA];
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == ERROR)
{
perror("server socket: ");
exit(-1);
}
server.sin_family = AF_INET;
server.sin_port = htons(atoi(argv[1])); // port num as an argument; atoi: char to int
server.sin_addr.s_addr = INADDR_ANY; // this tells your kernel to listen all inferfaces
bzero(&server.sin_zero, 8);
if ((bind(sock, (struct sockaddr *)&server, sockaddr_len)) == ERROR)
{
perror("bind :");
exit(-1);
}
if ((listen(sock, MAX_CLIENTS)) == ERROR)
{
perror("listen");
exit(-1);
}
while(true) // Better signal handling required
{
// returns client's socket descriptor which is used to send/receive data
if ((new = accept(sock, (struct sockaddr *)&client, &sockaddr_len)) == ERROR)
/*
* If it complains with an error message "invalid conversion from int to socklen", use this instead
* if ((cli = accept(sock, (struct sockaddr *)&client, (socklen_t*)&socketaddr_len)) == ERROR)
*/
{
perror("accept");
exit(-1);
}
printf("New Client connected from port no %d and IP %s\n", ntohs(client.sin_port), inet_ntoa(client.sin_addr));
data_len = 1;
while (data_len)
{
// receive data from the client on the socket descriptor new
// data_len= bytes of data
data_len = recv(new, data, MAX_DATA, 0);
// data is not zero send it back to the server
if (data_len)
{
// send data to the client
send(new, data, data_len, 0);
data[data_len] = '\0';
printf("Sent mesg: &s", data);
}
printf("Client disconnected\n");
close(new);
}
}
}
Terminal Command
./server port_no
TCP Echo Client Using Sockets
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h> // socket
#include <sys/socket.h> // socket
#include <netinet/in.h> // structure
#include <errno.h> // perror
#include <string.h>
#include <unistd.h> // sleep
#include <arpa/inet.h> // inet_addr
#define ERROR -1
#define BUFFER 1024
int main(int argc, char **argv)
{
struct sockaddr_in remote_server;
int sock;
char input[BUFFER]; // user input
char output[BUFFER]; // from the remote server
int len;
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == ERROR)
{
perror("socket");
exit(-1);
}
remote_server.sin_family = AF_INET;
remote_server.sin_port = htons(atoi(argv[2])); // char->int->network byte order
remote_server.sin_addr.s_addr = inet_addr(argv[1]);
bzero(&remote_server.sin_zero, 8);
if ((connect(sock, (struct sockaddr *)&remote_server, sizeof(struct sockaddr_in))) == ERROR)
{
perror("connect");
exit(-1);
}
// connection has been made
while (true)
{
// get input from the user
fgets(input, BUFFER, stdin);
send(sock, input, strlen(input), 0);
len = recv(sock, output, BUFFER, 0);
output[len] = '\0';
printf("%s\n", output);
}
close(sock);
}
Terminal Command
./client ip port