Creating Your Own Server: The Socket API, Part 1
2013-12-10 18:28
441 查看
转:http://www.linuxforu.com/2011/08/creating-your-own-server-the-socket-api-part-1/
By Pankaj Tanwar on August 1, 2011 in Coding, Developers · 2 Comments
In this series of articles aimed at newbies to network programming (knowledge of C is a prerequisite), we’ll learn how to create network clients and servers using the UNIX Socket API. We’ll start with creating simple server-client programs, and later on try something more complex. We’ll also try to understand how different servers work. I’ve tried to include a lot of details, but if you find some information missing, please feel free to comment.
Since we’re discussing sockets in network programming, newbies should first understand the OSI model layers, and the protocols used in these layers. Every layer in the model is responsible for doing some particular work, to make data transfer possible on the network. Each layer abstracts the lower layers’ work to the layer above it. I recommend that if you don’t know the ISO OSI (Open Systems Interconnection) Reference Model, you should read up on it. A good starting point is Wikipedia.
Here, we focus on the session layer (which establishes and maintains sessions) and the transport layer, which provides end-to-end reliable and unreliable delivery. Some protocols are TCP (for reliable connections), UDP (non-reliable connections) and SCTP (an advanced protocol with multiple-connection capability). Please also look at this and this for information on TCP/IP.
Here are some important features of TCP. It is a reliable protocol (the opposite of connection-less UDP, which we will look at in later articles). After transmitting a packet, it awaits an acknowledgement; if one is not returned, it retransmits the packet a number of times (depending upon the implementation). If the data cannot be transmitted, it notifies the user and closes the connection.
TCP decides how long to wait for an acknowledgement by the estimating RTT (Round Trip Time) between server and client. It also associates sequence numbers with segments, so that segments arriving out of order can be reordered at the receiver. Duplicate segments (retransmitted due to delays) can thus also be ignored. TCP provides flow control; the receiver can tell the sender how many bytes it is willing to receive, so that a slow receiver is not flooded.
TCP connections are full-duplex — the application can both send and receive data simultaneously.
Next, let’s look at a call to
A successful call to
AF stands for Address Family. We’re using
The
Next, let us set the address in
This is used to bind the socket descriptor
The
Next, let’s enter an infinite loop to keep on serving the client requests. Here we have to create another socket descriptor for the client, by calling
The
The newly created socket is not in the listening state. The original socket
Then, let us read a character (sent by the client to the server) from the descriptor with
The error handling I chose is based on the knowledge that these functions return a negative number on failure; I use
The flow of the client program is similar to the server. The first difference is that it specifies an Internet address for the server (the loop-back localhost address) in
Next, instead of listening, it calls the
Then, in the program, we have used
Then, run them:
Run each programs in a different terminal for a better view. See Figure 1 for the server’s output, and Figure 2 for the client’s.
Figure 1: Server running
Figure 2: Client's output
A good beginning, right? In the next article we’ll rewrite both these programs for IPv6, and move further to UDP. And yes, FOSS rocks!
Feature image credit: Emilian Robert Vicol. Reused under terms of CC-BY 2.0 License.
By Pankaj Tanwar on August 1, 2011 in Coding, Developers · 2 Comments
In this series of articles aimed at newbies to network programming (knowledge of C is a prerequisite), we’ll learn how to create network clients and servers using the UNIX Socket API. We’ll start with creating simple server-client programs, and later on try something more complex. We’ll also try to understand how different servers work. I’ve tried to include a lot of details, but if you find some information missing, please feel free to comment.
Since we’re discussing sockets in network programming, newbies should first understand the OSI model layers, and the protocols used in these layers. Every layer in the model is responsible for doing some particular work, to make data transfer possible on the network. Each layer abstracts the lower layers’ work to the layer above it. I recommend that if you don’t know the ISO OSI (Open Systems Interconnection) Reference Model, you should read up on it. A good starting point is Wikipedia.
Here, we focus on the session layer (which establishes and maintains sessions) and the transport layer, which provides end-to-end reliable and unreliable delivery. Some protocols are TCP (for reliable connections), UDP (non-reliable connections) and SCTP (an advanced protocol with multiple-connection capability). Please also look at this and this for information on TCP/IP.
Transmission Control Protocol (TCP)
TCP is a connection-oriented protocol that provides a reliable, full-duplex byte stream to users. Here, we will directly communicate with the transport layer, using TCP from the application layer, where users can communicate with the program.Here are some important features of TCP. It is a reliable protocol (the opposite of connection-less UDP, which we will look at in later articles). After transmitting a packet, it awaits an acknowledgement; if one is not returned, it retransmits the packet a number of times (depending upon the implementation). If the data cannot be transmitted, it notifies the user and closes the connection.
TCP decides how long to wait for an acknowledgement by the estimating RTT (Round Trip Time) between server and client. It also associates sequence numbers with segments, so that segments arriving out of order can be reordered at the receiver. Duplicate segments (retransmitted due to delays) can thus also be ignored. TCP provides flow control; the receiver can tell the sender how many bytes it is willing to receive, so that a slow receiver is not flooded.
TCP connections are full-duplex — the application can both send and receive data simultaneously.
Simple servers
Now let’s create a simple server to understand Internet sockets (server.c). Initially, our code will be for IPv4, but in later articles, we’ll look at IPv6, and then move to protocol-independent code.
About the code
The first thing to look at isstruct sockaddr_in. This structure is used to hold an Internet (IP) address in the
sin_addrmember, which is of the type
struct in_addrand holds a 32-bit unsigned integer. The port number is held in the
sin_portmember, an unsigned 16-bit integer (so port numbers must be less than 65536).
Next, let’s look at a call to
socket()(the
includesrequired are
sys/types.hand
sys/socket.h):
socket()returns a descriptor that will be used for end-point communication. The first argument,
domain, specifies a communication domain — the protocol family to be used for communication. According to
sys/sockets.h, these are:
Name | Purpose |
AF_UNIX, AF_LOCAL | Local communication |
AF_INET | IPv4 Internet protocols |
AF_INET6 | IPv6 Internet protocols |
AF_IPX | IPX — Novell protocols |
AF_NETLINK | Kernel user interface device |
AF_X25 | ITU-T X.25 / ISO-8208 protocol |
AF_AX25 | Amateur radio AX.25 protocol |
AF_ATMPVC | Access to raw ATM PVCs |
AF_APPLETALK | AppleTalk |
AF_PACKET | Low-level packet interface |
AF_INEThere — Internet IPv4. The next argument,
type, specifies the type of communication, from these choices:
SOCK_STREAM | Sequenced, reliable, two-way, connection-based byte stream (TCP,SCTP, etc) |
SOCK_DGRAM | Datagrams — connectionless, unreliable (UDP) |
SOCK_SEQPACKET | Sequenced, reliable, two-way, connection-based data transmission path for datagrams of fixed maximum length (SCTP) |
SOCK_RAW | Raw network protocol access (Transport layer protocols not required) |
protocolargument specifies a protocol to be used with the socket. Normally, only a single protocol exists to support a particular socket type within a given family (as specified within parentheses above). In such cases, this argument is 0.
Next, let us set the address in
sin_addr, as explained above. With the call to
socket(), a socket is created, but no address is assigned to it. So we have the
bind()function:
sockfdwith the address
addr; and
addrlenis its length. This is called assigning a name to the socket. Next up is
listen():
listen()call marks the socket referred to by
sockfdas a passive socket — one that will be used to accept incoming connections. The socket type should be
SOCK_STREAMor
SOCK_SEQPACKET, i.e., a reliable connection. The
backlogargument defines the maximum length of the queue of pending connections for
sockfd. If the queue grows above this, connections will be refused by clients.
Next, let’s enter an infinite loop to keep on serving the client requests. Here we have to create another socket descriptor for the client, by calling
accept. Now, whatever is written to this descriptor is sent to the client, and whatever is read from this descriptor is the data the client sent to the server:
accept()system call is used with socket types
SOCK_STREAMand
SOCK_SEQPACKET. 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 descriptor referring to that socket — in our program,
cfd.
The newly created socket is not in the listening state. The original socket
sockfdis unaffected by this call. The
addrargument contains the address of the remote machine to which we connect; since we don’t know the client’s address in advance, it’s NULL here. The
addrlenargument is the length of
addr— so, again, this is NULL.
Then, let us read a character (sent by the client to the server) from the descriptor with
read(), increment it, and write to the descriptor using
write(), to send the character to the client. Then close the descriptor by calling
close().
The error handling I chose is based on the knowledge that these functions return a negative number on failure; I use
perror()to display an error number message.
The client
And now the client (client.c). This client sends a character to the server running on port 29008 (or any arbitrary port):
sin_addr.
Next, instead of listening, it calls the
connect()system call to connect the socket referred to by
sockfdto the address specified by
addr. The returned descriptor will be used to communicate to the specified address.
Then, in the program, we have used
write()and
read()to send a character to the server, and receive a character, and then closed the descriptor.
Running the programs
Compile the programs as follows:Figure 1: Server running
Figure 2: Client's output
A good beginning, right? In the next article we’ll rewrite both these programs for IPv6, and move further to UDP. And yes, FOSS rocks!
Feature image credit: Emilian Robert Vicol. Reused under terms of CC-BY 2.0 License.
相关文章推荐
- Creating Your Own Server: The Socket API, Part 2
- Reporting Crashes in IMVU: Creating Your Very Own Symbol Server
- Berkeley Socket API – Creating a TCP/IP Server in C
- Creating Your Own Rails API Documentation
- [zz]Creating Your Very Own Symbol Server
- LINUX SOCKET PART 2: THE SERVER SIDE ISSUES
- iOS-Best Practices for Setting Up Your Local Device as a Peripheral(API Reference) the seventh part
- The Socket API, Part 3: Concurrent Servers
- The Socket API, Part 4: Datagrams
- PowerTip of the Day-Creating Your Own Types
- The Socket API, Part 5: SCTP
- Build your own CAB Part #1 - The Preamble(Jeremy D. Miller)
- 创建存储过程错误(已解决):Error Code : 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server ver
- 15 steps to launch your own startup in Europe - Part 5
- The API Gateway Pattern: Angular JS and Spring Security Part IV
- Tuning LAMP systems, Part 3: Tuning your MySQL server
- Build your own cryptographically safe server/client protocol
- Creating your own header file in C
- “ORA-12154: TNS: could not resolve the connect identifier specified” error while creating a linked server to Oracle
- Overloading the << Operator for Your Own Classes