Socket Communication in linux

Source: Internet
Author: User
Tags sendmsg htons
The communication model of socket communication in linux-general Linux technology-Linux programming and kernel information. The following is a detailed description. Guidance:
1. Socket Introduction
Socket is a TCP/IP network API that can be used to develop network applications. Socket data transmission is a special type of I/O, and Socket is also a file descriptor.
2. Establish Socket
Int socket (int domain, int type, int protocol)
Function return: an integer Socket descriptor that can be called later.
Parameter description:
Int domain: indicates the protocol family in use, usually PF_INET, indicating the network (TCP/IP) the protocol family describes the communication families (AF_UNIX and AF_INET) used by the host where the network program is located ).
AF_UNIX: can only be used for communication between processes in a single Unix system,
AF_INET: it is for the Internet and can allow communication between remote hosts (when we find that the domain option is PF _ * rather than AF _ * in man socket _*, because glibc is a posix implementation, it replaces AF with PF, but we can all use it)
Int type: Specifies the socket type, which is usually a SOCK_STREAM stream Socket. This will provide sequential, reliable, bidirectional, connection-oriented bit streams and SOCK_DGRAM datagram Socket will only provide fixed-length, unreliable, and connectionless communication.
Int prottocol: usually 0. Because we specify the type, we generally only need to replace it with 0.
Application Example: int sockfd = socket (PF_INET, SOCK_STREAM, 0 );
  
3. Socket Configuration
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.
After a socket descriptor is returned through a socket call, you must configure the socket before using the socket for network transmission:
1) The connection-oriented socket Client saves local and remote information in the socket data structure by calling the Connect function.
2) clients and servers that have no socket connection, and servers that are connected to the socket, call the bind function to configure local information.
  
4. Bind ()
The Bind function associates the socket with a port on the local machine, and then you can listen for service requests on this port.
Function prototype: int bind (int sockfd, struct sockaddr * my_addr, int addrlen );
Function return: 0 is returned when the call is successful; "-1" is returned when an error occurs, and errno is set to the corresponding error number.
Parameter description:
Sockfd: the socket descriptor returned by the socket function,
My_addr: A sockaddr pointer pointing to information including the local IP address and port number;
Addrlen: It is often set to sizeof (struct sockaddr ).
1> 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: generally AF_INET, representing the Internet (TCP/IP) address family;
Sa_data: contains the IP address and port number of the socket.
2> sockaddr_in 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 0 to keep the same size as struct sockaddr sin_zero to fill the sockaddr_in structure with the same length as struct sockaddr. You can use bzero () or the memset () function sets it to zero. */
};
This structure is more convenient to use.
The pointer to sockaddr_in and the pointer to sockaddr can be converted to each other, which means that if the parameter type required by a function is sockaddr, you can call a function to convert a pointer to ockaddr_in to a pointer to sockaddr, or vice versa. When using the bind function, you can automatically obtain the local IP address and randomly obtain an unused port number. The system randomly selects an unused port number and sets my_addr.sin_port to 0, the function automatically selects an unused port for you to use. Enter the local IP Address: 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 high byte priority, therefore, for machines that store data in Low-byte mode, data transmission over the Internet requires conversion. Otherwise, data inconsistency may occur.
Below are several bytes sequence conversion functions: (h: host n: network l: long s: short)
Htonl (): converts 32-bit values from the host's byte order to the network's byte order, and converts them to the high byte priority.
Htons (): converts 16-bit values from the host's byte order to the network's byte order, to a high byte priority
Ntohl (): converts 32-bit values from the byte sequence of the network to the host byte sequence.
Ntohs (): converts 16-bit values from the network byte order to the host byte order.
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.
Application Example:
A) Server
1) create a structure variable
Struct sockaddr_in my_addr;
Int SERVPORT;
  
2) configure the fill bit of the protocol family, port, address, and sin_zero
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 );
  
3) bind the local port, IP address, and connection protocol of sockfd
If (bind (sockfd, (struct sockaddr *) & my_addr, sizeof (struct sockaddr) =-1)
{
Perror ("bind ");
Return 1;
}
  
  
B) Client
1) Create struct variables and port numbers
Struct sockaddr_in serv_addr;
Struct hostent * host;
Int SERVPORT;
  
  
// Struct hostent * host; assign the Server IP address to the host struct through gethostbyname. If the incoming IP address is a domain name, convert it to an IP address and assign a value.
If (host = gethostbyname ("www.800hr.com") = NULL)
// Or if (host = gethostbyname ("192.168.0.1") = NULL)
{
Herror ("gethostbyname error ");
Return 1;
}
Else
{// Output IP Address: xxx. xxx
Printf ("host: % s \ n", inet_ntoa (* (struct in_addr *) host-> h_addr )));
}
  
  
2) Establish a Socket
If (sockfd = socket (AF_INET, SOCK_STREAM, 0) =-1)
{
Perror ("create sock ");
Return 1;
}
  
3) assign values to Server Structure Variables
Serv_addr.sin_family = AF_INET;
Serv_addr.sin_port = htons (SERVPORT );
Serv_addr.sin_addr = * (struct in_addr *) host-> h_addr );
Bzero (& (serv_addr.sin_zero), 8 );
  
4) connect to the server
// Int connect (int socfd, struct sockaddr * serv_addr, int addrlen)
For client program design, you do not need to call bind (), because in this case, you only need to know the IP address of the target machine, and you do not need to care about which port the customer uses 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 at the port.
  
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.
A connection-oriented server never starts a connection. It only passively listens to client requests on protocol ports.
No connection protocol never establishes direct connection.
  
If (connect (sockfd, (struct sockaddr *) & serv_addr, sizeof (struct sockaddr) =-1)
{
Perror ("create sock ");
Return 1;
}
  
5. Listen ()
The Listen function puts the socket in passive listening mode. It creates an input data queue for the socket and stores the incoming service requests in this queue until the program processes them.
Function prototype: int listen (int socfd, int backlog)
Parameter description:
Sockfd is the socket descriptor returned by the socket () function.
Backlog specifies the maximum number of requests allowed in the Request queue. incoming connection requests will wait for accept in the queue.
If the input queue is full when a service request arrives, the socket rejects the connection request and the customer receives an error message.
Application instance:
Int BACKLOG = 20;
If (listen (sockfd, BACKLOG) =-1)
{
Perror ("listen ");
Return 1;
}
  
6. accept ()
After the input queue is established, the server calls the accept function and then sleeps and waits for the client's connection request.
Function prototype: int accept (int sockfd, void * addr, int * addrlen );
Parameter description:
Socket descriptor listened to by sockfd
The pointer of the addr sockaddr_in variable, which is used to store the information of the Client requesting the service.
Addrlen is usually sizeof (struct sockaddr_in)
Returned value:-1 error. client_fd succeeded.
[Note]: When the socket monitored by the accept function receives a 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, the initial socket that receives the service request can continue to listen on the previous socket, and data transmission can be performed on the new socket descriptor.
Application instance:
Int client_fd;
Sin_size = sizeof (struct sockaddr_in );
If (client_fd = accept (sockfd, (struct sockaddr *) & remote_addr.sin_addr, & sin_size) =-1)
{
Perror ("accept ");
Continue;
}
  
7. send ()
Function prototype: int send (int sockfd, const void * msg, int len, int flags );
Parameter List:
Sockfd: the id of the socket party that receives data
Msg: pointer to send data
Len: the length of data in bytes.
Flags: generally 0
Returned value: Failed-1, number of bytes successfully sent
Application instance:
Char * msg = "Hello! ";
Int len, bytes_sent;
...
Len = strlen (msg );
Bytes_sent = send (client_fd, msg, len, 0 );
...
  
8. recv ()
Function prototype: int recv (int sockfd, void * buf, int len, unsigned int flags );
Parameter List:
Sockfd: fd of the socket for receiving data
Buf: data buffer for storing data
Len: len is the buffer length.
Flags: usually 0
Returned value: the number of bytes received successfully. Error-1.
Application instance:
While (1)
{
Recvbytes = recv (sockfd, buf, MAXDATASIZE, 0 );
If (recvbytes <= 0)
Break;
Fwrite (buf, 1, recvbytes, fp );
};
  
Recv and send
The recv and send functions provide similar functions as read and write, but they provide the fourth parameter to control read/write operations.
Int recv (int sockfd, void * buf, int len, int flags)
Int send (int sockfd, void * buf, int len, int flags)
The preceding three parameters are the same as read and write parameters. The fourth parameter can be a combination of 0 or below.
MSG_DONTROUTE: No route table
MSG_OOB: accept or send out-of-band data
MSG_PEEK: Views data and does not remove data from the system buffer.
MSG_WAITALL: waiting for all data
MSG_DONTROUTE: a sign used by the send function. This sign tells the IP protocol. The destination host is on the local network and there is no need to find the route table. This sign is generally used in network diagnostics and routing programs.
MSG_OOB: You can receive and send out-of-band data. We will explain this later.
MSG_PEEK: indicates the use of the recv function, indicating that the content is only read from the System Buffer, but the content of the system buffer is not clear. in this way, the content will remain the same for the next read. this flag can be used when multiple processes read and write data.
MSG_WAITALL: indicates the flag used by the recv function. It indicates that the recv is blocked until all the information arrives. If this flag is used, the recv is blocked until the specified condition is met or an error occurs.
1) when the specified byte is read, the function returns normally. Return value equals to len
2) when the end of the file is read, the function normally returns. The returned value is smaller than len.
3) When an operation error occurs,-1 is returned and the error code is set to errno ).
If flags is 0, the operation is the same as read and write. There are several other options, but we actually use very few. You can view Linux Programmer's Manual for detailed explanation.
  
Recvfrom and sendto
These two functions are generally used in non-Socket network programs (UDP) and we have learned before.
Recvmsg and sendmsg
Recvmsg and sendmsg can implement the functions of all the previous read and write functions.
Int recvmsg (int sockfd, struct msghdr * msg, int flags)
Int sendmsg (int sockfd, struct msghdr * msg, int flags)
Struct msghdr
{
Void * msg_name;
Int msg_namelen;
Struct iovec * msg_iov;
Int msg_iovlen;
Void * msg_control;
Int msg_controllen;
Int msg_flags;
}
  
Struct iovec
{
Void * iov_base;/* address at which the buffer starts */
Size_t iov_len;/* buffer length */
}
Msg_name and msg_namelen when the socket is not a connection-oriented (UDP), they store the address information of the receiver and the sender. msg_name is actually a pointer to struct sockaddr, and msg_name is the length of the structure. when the socket is connection-oriented, the two values should be NULL. msg_iov and msg_iovlen indicate the buffer content for receiving and sending. msg_iov is a structure pointer. msg_iovlen indicates the size of the structure array. msg_control and msg_controllen are the two variables used to receive and send control data. msg_flags specifies the operation options for receiving and sending control data. the options are the same as those of recv and send.
  
9. Socket disabling
There are two functions for closing the socket: close and shutdown. close is the same as closing the file.
Shutdown
Int shutdown (int sockfd, int howto)
TCP connections are bidirectional (read/write). When we use close, all read/write channels are closed. Sometimes we only want to close one direction, in this case, we can use shutdown. for different howto, different methods are used to disable the system. Howto = 0 at this time, the system will close the read channel. However, you can continue writing to the connected descriptor. howto = 1 to close the write channel. In contrast to the above, you can only read it. Howto = 2 close the read/write channel. Like close, if several sub-processes share a socket, if we use shutdown, all sub-processes cannot be operated. In this case, we can only use close to close the socket descriptor of the sub-process.
[Appendix]
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-1 if an error occurs, 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.
  
10. 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 parameter "how" allows you to select the following methods for the shutdown operation: "0" does not allow you to continue receiving data, "1" does not allow you to continue sending and receiving data. "2" does not allow you to continue sending and receiving 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.
  
11. IP and domain name Conversion
The IP address or domain name can be used to mark a machine on the network. How can we convert it?
Struct hostent * gethostbyname (const char * hostname)
Struct hostent * gethostbyaddr (const char * addr, int len, int type)
There is a definition of struct hostent in it
Struct hostent
{
Char * h_name;/* Host name */
Char * h_aliases;/* Host alias */
Int h_addrtype;/* Host address type AF_INET */
Int h_length;/* The host address length is 4 bytes and 32 characters for IP4 */
Char ** h_addr_list;/* List of Host IP addresses */
# Define h_addr h_addr_list [0]/* The first IP address of the Host */
}
Gethostbyname: You can convert a machine name (such as linux.yessun.com) to a structure pointer, in which domain name information is stored.
Gethostbyaddr: converts a 32-bit IP address (C0A80001) to a structure pointer.
When the two functions fail, return NULL and set the h_errno error variable. Call h_strerror () to obtain detailed error information.
Related Article

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.