Theoretically Socket is an interface between an application process and transport layer. The application process can send/receive messages to/from another application process (local or remote)via a socket.
In Unix technically a Socket is a file descriptor – an integer associated with an open file.
A socket address is the combination of an IP address (the location of the computer) and a port (which is mapped to the application program process) into a single identity .
An Internet socket is characterized by a unique combination of the following:
- Protocol: A transport protocol (e.g., TCP, UDP), raw IP, or others. TCP port 53 and UDP port 53 are different, distinct sockets.
- Local socket address: Local IP address and port number
- Remote socket address: Only for established TCP sockets. As discussed in the Client-Server section below, this is necessary since a TCP server may serve several clients concurrently. The server creates one socket for each client, and these sockets share the same local socket address.
Struct sockaddr_in {
short int sin_family; // set to AF_INET
unsigned short int sin_port; // Port number
struct in_addr sin_addr; // Internet address
unsigned char sin_zero[8]; //set to all zeros
};
struct in_addr {
unsigned long s_addr; // that’s a 32bit long, or 4 bytes
};
OS and Application that created Socket refer Socket by an unique Socket Identifier/Number.
Server : Computer processes that provide application services. It create Socket(in listening State) on start up.
Client : Any Program(local or remote) which want to use Application services provided by server. Client send request to listening socket of Server.
Two Important Types of Sockets are
Stream Sockets
- Connection oriented Sockets used in TCP.
- May serve several clients concurrently, by creating a child process for each client and establishing a TCP connection between the child process and the client.
- Unique dedicated sockets are created for each connection.
- Each socket is identified by both local and remote IP address and port.
Datagram Sockets
- Connectionless Sockets used in UDP.
- No child process is created for multiple clients.
- Single Socket serve all the clients.
- Socket is identified by local port no. and Ip address.
Sockets are usually implemented by an API library such as Berkeley sockets.
socket()
creates a new socket of a certain socket type, identified by an integer number, and allocates system resources to it.
int socket(int domain, int type, int protocol);
- domain should be set to PF_INET (PF_INET is protocol family, AF_INET is Address family)
- type can be SOCK_STREAM or SOCK_DGRAM(for TCP/UDP)
- set protocol to 0 to have socket choose the correct protocol based on type
- socket() returns a socket descriptor for use in later system calls or -1 on error
bind()
is typically used on the server side, and associates a socket with a socket address structure, i.e. a specified local port number and IP address.
int bind(int sockfd, struct sockaddr *my_addr, int addrlen)
- sockfd is the socket descriptor returned by socket()
- my_addr is pointer to struct sockaddr that contains information about your IP address and port
- addrlen is set to sizeof(struct sockaddr)
- returns -1 on error
- my_addr.sin_port = 0; //choose an unused port at random
- my_addr.sin_addr.s_addr = INADDR_ANY; //use my IP adr
listen()
is used on the server side, and causes a bound TCP socket to enter listening state.
int listen(int sockfd, int backlog);
- sockfd is the socket file descriptor returned by socket()
- backlog is the number of connections allowed on
- the incoming queue
- listen() returns -1 on error
- Need to call bind() before you can listen()
connect()
is used on the client side, and assigns a free local port number to a socket. In case of a TCP socket, it causes an attempt to establish a new TCP connection.
int connect(int sockfd, struct sockaddr *serv_addr, int addrlen)
- sockfd is the socket descriptor returned by socket()
- serv_addr is pointer to struct sockaddr that
- contains information on destination IP address and port
- addrlen is set to sizeof(struct sockaddr)
- returns -1 on error
accept()
is used on the server side. It accepts a received incoming attempt to create a new TCP connection from the remote client, and creates a new socket associated with the socket address pair of this connection.
int accept(int sockfd, void *addr, int *addrlen);
- sockfd is the listening socket descriptor
- information about incoming connection is stored in
- addr which is a pointer to a local struct sockaddr_in
- addrlen is set to sizeof(struct sockaddr_in)
- accept returns a new socket file descriptor to use
- for this accepted connection and -1 on error
send()
and recv()
, or write()
and read()
, or recvfrom()
and sendto()
, are used for sending and receiving data to/from a remote socket.
int send(int sockfd, const void *msg, int len, int flags);
- sockfd is the socket descriptor you want to send data to (returned by socket() or got from accept())
- msg is a pointer to the data you want to send
- len is the length of that data in bytes
- set flags to 0 for now
- sent() returns the number of bytes actually sent (may
- be less than the number you told it to send) or -1 on error
int recv(int sockfd, void *buf, int len, int flags);
- sockfd is the socket descriptor to read from
- buf is the buffer to read the information into
- len is the maximum length of the buffer
- set flags to 0 for now
- recv() returns the number of bytes actually read into the buffer or -1 on error
- If recv() returns 0, the remote side has closed connection on you
close()
causes the system to release resources allocated to a socket. In case of TCP, the connection is terminated.
int close(int sockfd);
- Closes connection corresponding to the socket descriptor and frees the socket descriptor
- Will prevent any more sends and recvs
gethostbyname()
and gethostbyaddr()
are used to resolve host names and addresses.
select()
is used to prune a provided list of sockets for those that are ready to read, ready to write or have errors
poll()
is used to check on the state of a socket. The socket can be tested to see if can be written to, read from or has errors.
Sample Server File
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>/* the port users will be connecting to */
#define MYPORT 3490/* how many pending connections queue will hold */
#define BACKLOG 10void sigchld_handler(int s)
{
while(wait(NULL) > 0);
}
int main(int argc, char *argv[ ])
{/* listen on sock_fd, new connection on new_fd */
int sockfd, new_fd;
/* my address information */
struct sockaddr_in my_addr;
/* connector’s address information */
struct sockaddr_in their_addr;
int sin_size;
struct sigaction sa;
int yes = 1;
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror(“Server-socket() error lol!”);
exit(1);
} else {printf(“Server-socket() sockfd is OK…\n”);
}if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
{
perror(“Server-setsockopt() error lol!”);
exit(1);
} else{
printf(“Server-setsockopt is OK…\n”);
}/* host byte order */
my_addr.sin_family = AF_INET;
/* short, network byte order */
my_addr.sin_port = htons(MYPORT);
/* automatically fill with my IP */
my_addr.sin_addr.s_addr = INADDR_ANY;
//convert binary ip to string we use inet_ntoa
printf(“Server-Using %s and port %d…\n”, inet_ntoa(my_addr.sin_addr), MYPORT);/* zero the rest of the struct */
memset(&(my_addr.sin_zero), ”, 8);
if(bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1)
{
perror(“Server-bind() error”);
exit(1);
}
else
printf(“Server-bind() is OK…\n”);
if(listen(sockfd, BACKLOG) == -1)
{
perror(“Server-listen() error”);
exit(1);
}
printf(“Server-listen() is OK…Listening…\n”);
/* clean all the dead processes */
sa.sa_handler = sigchld_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if(sigaction(SIGCHLD, &sa, NULL) == -1)
{
perror(“Server-sigaction() error”);
exit(1);
}
else
printf(“Server-sigaction() is OK…\n”);
/* accept() loop */
while(1) {
sin_size = sizeof(struct sockaddr_in);
if((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) == -1) {
perror(“Server-accept() error”);
continue;
} else {printf(“Server-accept() is OK…\n”);
}printf(“Server-new socket, new_fd is OK…\n”);
printf(“Server: Got connection from %s\n”, inet_ntoa(their_addr.sin_addr));
/* this is the child process */
if(!fork()) {
/* child doesn’t need the listener */
close(sockfd);
if(send(new_fd, “This is a test string from server!\n”, 37, 0) == -1)
perror(“Server-send() error lol!”);
close(new_fd);
exit(0);
}
else
printf(“Server-send is OK…!\n”);
/* parent doesn’t need this*/
close(new_fd);
printf(“Server-new socket, new_fd closed successfully…\n”);
}
return 0;
}
Sample Client File
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
// the port client will be connecting to
#define PORT 3490
// max number of bytes we can get at once
#define MAXDATASIZE 300int main(int argc, char *argv[])
{int sockfd, numbytes;
char buf[MAXDATASIZE];
struct hostent *he;
// connector’s address information
struct sockaddr_in their_addr;
// if no command line argument supplied
if(argc != 2) {
fprintf(stderr, “Client-Usage: %s the_client_hostname\n”, argv[0]);
// just exit
exit(1);
}
// get the host info
if((he=gethostbyname(argv[1])) == NULL) {
perror(“gethostbyname()”);
exit(1);
} else {
printf(“Client-The remote host is: %s\n”, argv[1]);
}if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror(“socket()”);
exit(1);
} else {
printf(“Client-The socket() sockfd is OK…\n”);
}
// host byte order
their_addr.sin_family = AF_INET;
// short, network byte order
printf(“Server-Using %s and port %d…\n”, argv[1], PORT);
their_addr.sin_port = htons(PORT);
their_addr.sin_addr = *((struct in_addr *)he->h_addr);
// zero the rest of the struct
memset(&(their_addr.sin_zero), ”, 8);
if(connect(sockfd, (struct sockaddr *)&their_addr, sizeof(struct sockaddr)) == -1)
{
perror(“connect()”);
exit(1);
} else {
printf(“Client-The connect() is OK…\n”);
}if((numbytes = recv(sockfd, buf, MAXDATASIZE-1, 0)) == -1) {
perror(“recv()”);
exit(1);
} else {
printf(“Client-The recv() is OK…\n”);
}
buf[numbytes] = ”;
printf(“Client-Received: %s”, buf);
printf(“Client-Closing sockfd\n”);
close(sockfd);
return 0;
}
January 18, 2010 at 8:46 pm |
hey…did this socket code will work well for windows as well??i think for socket programming in windows we have to replace socket,h with winsock.h…. n 1 more query….well all the libraries included in the code r already present or they r to be included externally??
January 19, 2010 at 7:35 am |
This code is using Berkeley Sockets not winsocks hence will not work in windows but some changes will make it work. If u are using GCC compiler then there is no need to install any libraries.