Socket network programming in linux

Source: Internet
Author: User
Tags socket error htons

Network Socket data transmission is a special type of I/O, and Socket is also a file descriptor. Socket also has a function called Socket () similar to opening a file. This function returns an integer Socket descriptor, and subsequent connection establishment and data transmission operations are implemented through this Socket.

What is Socket
A Socket interface is an API of a TCP/IP network. A Socket interface defines many functions or routines that can be used by programmers to develop applications on a TCP/IP network. To learn TCP/IP network programming on the Internet, you must understand the Socket interface.
 
The Socket interface designer first places the interface in the Unix operating system. If you understand the input and output of Unix systems, you can easily understand Socket. Network
Socket data transmission is a special type of I/O, and Socket is also a file descriptor. Socket also has a function that calls Socket () similar to opening a file.
Return to an integer Socket descriptor. Subsequent connection establishment and data transmission operations are implemented through this Socket. There are two common Socket types: stream Socket
(SOCK_STREAM) and datagram Socket (SOCK_DGRAM ). Stream is a connection-oriented Socket for connection-oriented TCP Service applications; Data
The reporting Socket is a connectionless Socket that corresponds to a connectionless UDP Service Application.
Socket Creation
To establish a Socket, the program can call the Socket function, which returns a handle similar to a file descriptor. The socket function is prototype:
Int socket (int domain, int type, int protocol );
 
Domain indicates the protocol family used, usually PF_INET, indicating the Internet protocol family (TCP/IP protocol family). The type parameter specifies the socket type:
SOCK_STREAM
Or SOCK_DGRAM, the Socket interface also defines the original Socket (SOCK_RAW), allowing the program to use the low-layer protocol; protocol is usually assigned a value of "0 ".
The Socket () call returns an integer socket descriptor, which you can use later.
The Socket descriptor is a pointer to the internal data structure and points to the descriptor table entry. When the Socket function is called, the socket execution body establishes a Socket. In fact, "Creating a Socket" means allocating storage space for a Socket data structure. The Socket execution body manages the descriptor table for you.
A network connection between two network programs includes five types of information: communication protocol, local Protocol address, local host port, remote host address, and remote protocol port. The Socket data structure contains these five types of information.
Socket Configuration
 
After a socket descriptor is returned through a socket call, you must configure this socket before using the socket for network transmission. Connection-oriented socket Client
Call the Connect function to save local and remote information in the socket data structure. The client and server that have no socket connection and the server that is connected to the socket are called
Bind function to configure local information.
The Bind function associates the socket with a port on the local machine, and then you can listen for service requests on this port. The Bind function is prototype:
Int bind (int sockfd, struct sockaddr * my_addr, int addrlen );
Sockfd is the socket descriptor returned by the socket function. my_addr is a sockaddr pointer pointing to information including the local IP address and port number. addrlen is often set to sizeof (struct sockaddr ).
The struct sockaddr structure type is used to save socket information:
Struct sockaddr {
Unsigned short sa_family;/* address family, AF_xxx */
Char sa_data [14];/* 14-byte Protocol address */
};
Sa_family is generally AF_INET, which represents the Internet (TCP/IP) address family. sa_data contains the IP address and port number of the socket.
There is also a structure type:
Struct sockaddr_in {
Short int sin_family;/* address family */
Unsigned short int sin_port;/* Port Number */
Struct in_addr sin_addr;/* IP Address */
Unsigned char sin_zero [8];/* fill in 0 to keep the same size as struct sockaddr */
};
 
This structure is more convenient to use. Sin_zero is used to fill the sockaddr_in structure with struct
The same length of sockaddr can be set to zero using the bzero () or memset () function. Pointing to sockaddr_in
The pointer to sockaddr and the pointer to sockaddr can be converted to each other, which means that if the required parameter type of a function is sockaddr, you can
The addr_in pointer is converted to the sockaddr pointer; or vice versa.
When using the bind function, you can use the following value assignment to automatically obtain the local IP address and randomly obtain an unused port number:
My_addr.sin_port = 0;/* The system randomly selects an unused Port Number */
My_addr.sin_addr.s_addr = INADDR_ANY;/* enter the local IP Address */
By setting my_addr.sin_port to 0, the function automatically selects an unused port for you to use. Similarly, by setting my_addr.sin_addr.s_addr to INADDR_ANY, the system automatically fills in the local IP address.
Note that when using the bind function, you need to convert sin_port and sin_addr to the network byte priority, while sin_addr does not need to be converted.
There are two types of computer data storage priorities: high byte priority and low byte priority. Data on the Internet is transmitted over the network in the high byte priority. Therefore, for machines that store data in the low byte priority mode, data transmission over the Internet requires conversion, otherwise, data inconsistency may occur.
Below are several bytes sequence conversion functions:
· Htonl (): converts 32-bit values from the host's byte order to the network's byte order
· Htons (): converts 16-bit values from the host's byte order to the network's byte order
· Ntohl (): converts 32-bit values from the network byte order to the host byte order.
· Ntohs (): converts 16-bit values from the network byte order to the host byte order.
The Bind () function returns 0 when the call is successful. If an error occurs, it returns "-1" and sets errno as the corresponding error number. Note that do not set the port number to a value smaller than 1024 when calling the bind function, because the port numbers from 1 to 1024 are reserved, you can select any unused port number in the range greater than 1024.
Establish a connection
Connection-oriented client programs use the Connect function to configure the socket and establish a TCP connection with the remote server. The function prototype is:
Int connect (int sockfd, struct sockaddr * serv_addr, int addrlen );
Sockfd
Is the socket descriptor returned by the socket function; serv_addr is a pointer containing the IP address and port number of the remote host; addrlen is the length of the remote geological structure.
When an error occurs, the Connect function returns-1 and sets errno as the corresponding error code. You do not need to call bind () for client program design, because in this case, you only need to know the target machine
But the customer does not need to worry about which port to establish a connection with the server. The socket execution body automatically selects an unused port for your program and notifies you when the program data will arrive
Interrupt.
Connect function starts a direct connection with the remote host. The socket must be connected to the remote host only when the connection-oriented client program uses the socket. No connection protocol never establishes direct connection. The connection-oriented server never starts a connection, but passively listens to customer requests on the protocol port.
The Listen function enables the socket to be in passive listening mode and creates an input data queue for the socket. The incoming service requests are stored in the queue until the program processes them.
Int listen (int sockfd, int backlog );
Sockfd
Is the Socket returned by the socket System Call.
Descriptor; backlog specifies the maximum number of requests allowed in the Request queue. incoming connection requests will wait for accept () in the queue (refer to the following ). Backlog waits for the queue
The number of requests for the service is limited. The default value for most systems is 20. If a service request arrives, the input queue is full, and the socket rejects the connection request, the customer will receive an error message.
When an error occurs, the listen function returns-1 and returns the error code errno.
The accept () function allows the server to receive client connection requests. After the input queue is established, the server calls the accept function and then sleeps and waits for the client's connection request.
Int accept (int sockfd, void * addr, int * addrlen );
 
 
Sockfd is the socket descriptor to be listened on. addr is usually a pointer to the sockaddr_in variable, which is used to store the information of the host requesting the service (
A host sends this request from a port). The addrten is usually directed to a sizeof (struct
Sockaddr_in. When an error occurs, the accept function returns-1 and sets the corresponding errno value.
First, when the accept function monitors
When the socket receives the connection request, the socket execution body establishes a new socket, and the execution body associates the new socket with the address of the Request connection process, and receives
The initial socket can still be listened on the previous socket, and data transmission can be performed on the new socket descriptor.
Data Transmission
The Send () and recv () functions are used for data transmission on the connected socket.
The Send () function is prototype:
Int send (int sockfd, const void * msg, int len, int flags );
Sockfd is the socket descriptor you want to use to transmit data; msg is a pointer to the data to be sent; Len is the length of the data in bytes; flags is usually set to 0 (for the usage of this parameter, refer to the man Manual ).
The Send () function returns the number of actually sent bytes, which may be less than the data you want to Send. In the program, the return value of send () should be compared with the number of bytes to be sent. When the return value of send () does not match len, this situation should be processed.
Char * msg = "Hello! ";
Int len, bytes_sent;
......
Len = strlen (msg );
Bytes_sent = send (sockfd, msg, len, 0 );
......
The recv () function is prototype:
Int recv (int sockfd, void * buf, int len, unsigned int flags );
Sockfd is the socket descriptor for receiving data, buf is the buffer for storing received data, and len is the buffer length. Flags is also set to 0. Recv () returns the number of actually received bytes. If an error occurs,-1 is returned and the corresponding errno value is set.
Sendto () and recvfrom () are used for data transmission in the connectionless datagram socket mode. Because the local socket does not establish a connection with the remote machine, the destination address should be specified when sending data.
The prototype of the sendto () function is:
Int sendto (int sockfd, const void * msg, int len, unsigned int flags, const struct sockaddr * to, int tolen );
This function has two more parameters than the send () function. to indicates the IP address and port number of the host, while tolen is often assigned sizeof (struct sockaddr ). The Sendto function also returns the actual length of data bytes or-1 in case of a sending error.
The original Recvfrom () function is:
Int recvfrom (int sockfd, void * buf, int len, unsigned int flags, struct sockaddr * from, int * fromlen );
 
From is a variable of the struct sockaddr type, which saves the IP address and port number of the source machine. Fromlen is often set to sizeof (struct
Sockaddr ). When recvfrom () is returned, fromlen contains the number of data bytes actually stored in from. The Recvfrom () function returns the number of bytes received or
If an error occurs,-1 is returned and the corresponding errno is set.
If you call the connect () function on the datagram socket, you can also use send () and recv () for data transmission, but the socket is still a datagram socket, the UDP Service at the transport layer is used. However, when sending or receiving data reports, the kernel automatically adds the object and source address information.
End Transmission
After all data operations are completed, you can call the close () function to release the socket and stop any data operations on the socket:
Close (sockfd );
You can also call the shutdown () function to close the socket. This function allows you to stop data transmission in a certain direction, while data transmission in one direction continues. For example, you can close the write operation of a socket and allow the socket to continue to accept data until all data is read.
Int shutdown (int sockfd, int how );
Sockfd is the descriptor of the socket to be closed. The how parameter allows you to select the following methods for the shutdown operation:
· 0 ------- you are not allowed to continue receiving data.
· 1 ------- data cannot be sent again
· 2 ------- you are not allowed to send or receive data,
· If both allow, close () is called ()
If the shutdown operation succeeds, 0 is returned. If an error occurs,-1 is returned and the corresponding errno is set.
Socket programming instance
The server in the Code instance sends the string "Hello, you are connected!" to the client through a socket connection! ". If you run the software on the server and the client runs the software on the client, the client receives the string.
The software code of the server is as follows:
# Include
# Include
# Include
# Include
# Include
# Include
# Include
# Include
# Define servport 3333/* server listening port number */
# Define backlog 10/* Maximum number of simultaneous connection requests */
Main ()
{
Int sockfd, client_fd;/* sock_fd: Listen to socket; client_fd: Data Transmission socket */
Struct sockaddr_in my_addr;/* local address information */
Struct sockaddr_in remote_addr;/* client address information */
If (sockfd = socket (af_inet, sock_stream, 0) =-1 ){
Perror ("socket creation error! "); Exit (1 );
}
My_addr.sin_family = af_inet;
My_addr.sin_port = htons (servport );
My_addr.sin_addr.s_addr = inaddr_any;
Bzero (& (my_addr.sin_zero), 8 );
If (BIND (sockfd, (struct sockaddr *) & my_addr, sizeof (struct sockaddr) =-1 ){
Perror ("BIND error! ");
Exit (1 );
}
If (listen (sockfd, BACKLOG) =-1 ){
Perror ("listen error! ");
Exit (1 );
}
While (1 ){
Sin_size = sizeof (struct sockaddr_in );
If (client_fd = accept (sockfd, (struct sockaddr *) & remote_addr, & sin_size) =-1 ){
Perror ("accept error ");
Continue;
}
Printf ("received a connection from % s \ n", inet_ntoa (remote_addr.sin_addr ));
If (! Fork () {/* child process code segment */
If (send (client_fd, "Hello, you are connected! \ N ", 26, 0) =-1)
Perror ("send error! ");
Close (client_fd );
Exit (0 );
}
Close (client_fd );
}
}
}
 
The workflow of the server is as follows: first call the socket function to create a Socket, then call the bind function to bind it to the local address and a local port number, and then call
Listen listens on the corresponding socket. When accpet receives a connection service request, a new socket is generated. The server displays the IP address of the client and
The new socket sends the string "Hello, you are connected! ". Close the socket.
The fork () function in the Code instance generates a sub-process to process the data transmission part. The value returned by the fork () Statement for the sub-process is 0. Therefore, the if statement containing the fork function is the sub-process code part, and it is executed concurrently with the parent Process Code part after the if statement.
The client code is as follows:
# Include
# Include
# Include
# Include
# Include
# Include
# Include
# Include
# Define SERVPORT 3333
# Define MAXDATASIZE 100/* maximum data transmission volume each time */
Main (int argc, char * argv []) {
Int sockfd, recvbytes;
Char buf [MAXDATASIZE];
Struct hostent * host;
Struct sockaddr_in serv_addr;
If (argc h_addr );
Bzero (& (serv_addr.sin_zero), 8 );
If (connect (sockfd, (struct sockaddr *) & serv_addr ,\
Sizeof (struct sockaddr) =-1 ){
Perror ("connect error! ");
Exit (1 );
}
If (recvbytes = recv (sockfd, buf, MAXDATASIZE, 0) =-1 ){
Perror ("recv error! ");
Exit (1 );
}
Buf [recvbytes] = '\ 0 ';
Printf ("Received: % s", buf );
Close (sockfd );
}
The client first obtains the Server IP address through the server domain name, creates a socket, calls the connect function to establish a connection with the server, receives data sent from the server after the connection is successful, and closes the socket.
The gethostbyname () function completes domain name conversion. Because IP addresses are hard to remember and read/write, domain names are often used to represent hosts for convenience, which requires domain name and IP address conversion. Function prototype:
Struct hostent * gethostbyname (const char * name );
The structure type returned by the function as hosten. Its definition is as follows:
Struct hostent {
Char * h_name;/* Host's official domain name */
Char ** h_aliases;/* an array of host aliases ending with NULL */
Int h_addrtype;/* return address type, in the Internet environment is AF-INET */
Int h_length;/* the length of the address in bytes */
Char ** h_addr_list;/* an array ending with 0, containing all addresses of the Host */
};
# Define h_addr h_addr_list [0]/* The first address in h-addr-list */
When gethostname () is called successfully, a pointer to struct hosten is returned. If the call fails,-1 is returned. When gethostbyname is called, you cannot use the perror () function to output error information. Instead, use the herror () function to output error information.
The principle of a connectionless client/server program is the same as that of a connected Client/Server. The difference between the two is that customers in a connectionless Client/Server generally do not need to establish a connection, when sending and receiving data, you must specify the address of the remote machine.
Blocking and non-blocking
 
The blocking function does not allow the program to call another function until it completes the specified task. For example, when a program executes a function call to read data, the next program statement is not executed until the function completes the read operation. When
When the server runs an accept statement without a client connection request, the server stops waiting for the connection request on the accept statement. This is called blocking.
(Blocking ). The non-blocking operation can be completed immediately. For example, if you want the server to check whether a client is waiting for a connection, the server will accept the connection; otherwise, the server will continue to do other things.
You can set the Socket to a non-blocking method. The non-blocking socket enables the accept call to return immediately when no client is waiting.
# Include
# Include
......
Sockfd = socket (af_inet, sock_stream, 0 );
Fcntl (sockfd, f_setfl, o_nonblock );
......
 
By setting the socket as a non-blocking method, you can implement "polling" Several sockets. When you attempt to read data from a non-blocking socket without data waiting for processing, the function will return immediately
-1 is returned, and errno is set to ewouldblock. However, this "Round Robin" will make the CPU in a busy waiting mode, thus reducing performance and wasting system resources. And call
Select () effectively solves this problem. It allows you to hook up the process itself and enable the system kernel to listen to any activity of a set of file descriptors required by the system kernel, just confirm in any monitored File
If there is an activity on the descriptor, the Select () call will return information indicating that the file descriptor has been prepared, so as to select random changes for the process, it is not a waste of testing input by the process itself.
CPU overhead. The prototype of the select function is:
Int select (INT numfds, fd_set * readfds, fd_set * writefds,
Fd_set * required TFDs, struct timeval * timeout );
 
Readfds, writefds, and limit TFDs are the collection of read, write, and exception handling file descriptors monitored by select. If you want to confirm whether it is OK
To read data from the standard input and a socket descriptor, you only need to add the file descriptor 0 and the corresponding sockdtfd to the readfds set; numfds Value
Is the file descriptor with the highest number to be checked plus 1. In this example, the numfds value should be sockfd + 1. When the select statement returns, readfds will be modified to indicate a file.
The descriptor is ready to be read. You can test it through FD_ISSSET. To set, reset, and test the file descriptor corresponding to fd_set, it provides a set of macros:
FD_ZERO (fd_set * set) ---- clears a file descriptor set;
FD_SET (int fd, fd_set * set) ---- Add a file descriptor to the file descriptor set;
FD_CLR (int fd, fd_set * set) ---- clears a file descriptor from the file descriptor set;
FD_ISSET (int fd, fd_set * set) ---- try to determine whether the file descriptor is set.
The Timeout parameter is a pointer to the struct timeval type, which enables select () to return if no file descriptor is ready after waiting for a long time. Struct timeval data structure:
Struct timeval {
Int TV _sec;/* seconds */
Int TV _usec;/* microseconds */
};
POP3 client instance
The following code instance is based on the POP3 client protocol and connects to the mail server and retrieves emails from a specified user account. Commands that interact with the email server are stored in the string array POPMessage. The program sends these commands in sequence through a do-while loop.
# Include
# Include
# Include
# Include
# Include
# Include
# Include
# Include
# Define POP3SERVPORT 110
# Define maxdatasalize 4096
Main (int argc, char * argv []) {
Int sockfd;
Struct hostent * host;
Struct sockaddr_in serv_addr;
Char * POPMessage [] = {
"USER userid \ r \ n ",
"PASS password \ r \ n ",
"STAT \ r \ n ",
"LIST \ r \ n ",
"RETR 1 \ r \ n ",
"DELE 1 \ r \ n ",
"QUIT \ r \ n ",
NULL
};
Int iLength;
Int iMsg = 0;
Int iEnd = 0;
Char buf [MAXDATASIZE];
If (host = gethostbyname ("your. server") = NULL ){
Perror ("gethostbyname error ");
Exit (1 );
}
If (sockfd = socket (af_inet, sock_stream, 0) =-1 ){
Perror ("socket error ");
Exit (1 );
}
Serv_addr.sin_family = af_inet;
Serv_addr.sin_port = htons (pop3servport );
Serv_addr.sin_addr = * (struct in_addr *) Host-> h_addr );
Bzero (& (serv_addr.sin_zero), 8 );
If (connect (sockfd, (struct sockaddr *) & serv_addr, sizeof (struct sockaddr) =-1 ){
Perror ("Connect error ");
Exit (1 );
}
Do {
Send (sockfd, popmessage [imsg], strlen (popmessage [imsg]), 0 );
Printf ("have sent: % s", popmessage [imsg]);
Ilength = Recv (sockfd, BUF + iend, sizeof (BUF)-iend, 0 );
Iend + = ilength;
Buf [iend] = '\ 0 ';
Printf ("Received: % s, % d \ n", Buf, imsg );
Imsg ++;
} While (popmessage [imsg]);
Close (sockfd );
}


Socket function API. cpp

Htons (); // converts the short type value from the host's byte order to the network's byte order

Inet_addr (); // converts an IP address string to a long network byte

Gethostbyname (); // obtain the IP address corresponding to the domain name

Inet_ntoa (); // converts long network byte to an IP address string

This article is from the ChinaUnix blog. If you want to view the original text, click:Http://blog.chinaunix.net/u2/72751/showart_1088738.html

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.