Transformation of the data storage precedence order
The computer data store has two byte precedence: The high byte takes precedence (called the big-endian mode) and the low-order byte precedence (known as the small-end mode). The low address of memory stores the low byte of the data, and the high address stores the data in a high-byte manner called the small-end mode. The high address of the memory stores the low bytes of data, and the low address stores the data in a high-byte manner called the big-endian mode.
Eg: for the number of 0x12345678 in memory (note that for data, here 12 is high byte, 78 is low byte; for address, the left is the low address, the right side is the high address)
If it is stored in big-endian mode, its true number is: 0x12345678
If it is stored in a small-end mode, its true number is: 0x78563412
Comprehensive: small-end mode, the first low-byte, big-endian mode first save high bytes.
If the byte order used by a system is called the host byte order, it may be a small-ended or big-endian mode. Usually our computer stores data in small-end mode. While the port number and IP address are stored in the network byte order, not the host byte order, the network byte order is the big-endian mode. To match the host byte order and the network byte order with each other, we need to convert each of the two byte storage priorities.
Pra1 original question
The implementation converts the IP address (dotted decimal number) stored as a string into a 32-bit binary value of the host's byte order. IP is: "180.97.33.107". Hex is b4.61.21.6b
Ideas
In general, our host byte order is the small-endian byte order, that is, the selection of low-byte data storage.
1. Remove each number in the string
2. Shift Left (note that the left shift is bound to be 0)
180:00 xx B4 left shift 0-digit XX b4
97:00 00 00 61 Shift Left 8 bits 00 00 61 00
33:00 00 00 21 Shift left 16 bits 00 21 00 00
107:00 6b shift left 24 Bits 6b 00 00 00
3. OR operation
#include <stdio.h> #include <stdlib.h> #include <string.h> #define IP "180.97.33.107"/* The IP address is converted to the binary value of the host byte order, and the output is represented by a 16 binary */static int My_atoh (char *ip) { int arr[4];/* for holding 4 integers deducted from the IP address */ int my_ip; SSCANF (IP, "%d.%d.%d.%d", arr,arr+1,arr+2,arr+3); My_ip = (Arr[3] << 24) | (Arr[2] << 16) | (Arr[1] << 8) | ARR[0]; return my_ip;} int main (int argc, char *argv[]) { int my_host = My_atoh (IP); printf ("IP :%s \ n", IP); printf ("Host:%x \ n", my_host); return 0;}
Pra2 original question
The implementation converts the host byte-order (small-end mode) into a network byte order (in big-endian mode storage). That is, the host byte order is 6b2161b4–> b461216b
Idea 1
Swap the 6b with B4, 21 and 61.
#include <stdio.h>int my_hton (int ip) {/ * &ip points to an integer IP with 32 bits, converts a pointer of the int* type to a pointer of type char*, * PTR points to integers with 8 bits (第0-7位), * ptr+1 points to integers with 8 bit representation (第8-15位), * ptr+2 points to integers with 8 bits (第16-23位), * ptr+ 3 points to the integer number that represents (第24-31位) with 8 bits. */
char *ptr = (char*) & IP; char tmp; TMP = ptr[0]; Ptr[0] = ptr[3]; PTR[3] = tmp; TMP = ptr[1]; PTR[1] = ptr[2]; PTR[2] = tmp; return IP;} int main (int argc, char *argv[]) { int my_host = 0X6B2161B4; int my_net = My_hton (my_host); printf ("My_host:%x \ n", my_host); printf ("My_net:%x \ n", my_net); return 0;}
In fact, the IP address is dotted decimal, with each byte representing a range of 0-255. Our char type usually defaults to a signed number, meaning that it represents a range of-128-127. So is the part that I marked yellow in the code wrong? In fact, there is no mistake, because here we are only concerned about the storage of each bit of IP, does not require the actual decimal value of each byte. When formatted with printf, the output is formatted according to the binary form of the data in memory, and the 16 binary form is not negative.
Idea 2
1. For 0X6B2161B4, first move right and proceed with operation, take out each byte
For example: To remove 6b, then 0x6b2161b4 to the right 24 bits, and then with the 0xFF operation can
Note: You must not proceed with the operation first, and then move right. For example, to remove 6b, first make 0X6B2161B4 and 0xff000000 with operation, then move right 24 bits. This is wrong because the right shift will complement the sign bit. (Tips: Shift left 0 and discard symbol bits)
2. Move left again and adjust to the appropriate position. (The following two steps are similar to PRA1)
3. OR operation
#include <stdio.h>int my_hton2 (int ip) { int my_net; My_net = ((ip&0xff) <<24) | (((ip>>8) &0xff) << 16) | (((ip>>16) &0xff) << 8) | ((ip>>24) &0xff); return my_net;} int main (int argc, char *argv[]) { int my_host = 0X6B2161B4; int my_net = My_hton2 (my_host); printf ("My_host:%x \ n", my_host); printf ("My_net:%x \ n", my_net); return 0;}
Implementation converts network byte order to dotted decimal
#include <stdio.h>static char* my_ntoa (int ip) { static char buf[1024] = ""; sprintf (buf, "%d.%d.%d.%d", (IP >>) & 0xff, (IP >> +) & 0xff, (IP >> 8) & 0xFF, IP & 0x FF); return BUF;} int main (int argc,char *argv[]) { int my_net = 0xb461216b; printf ("My_net:%x \ n", my_net); printf ("IP :%s \ n", My_ntoa (my_net)); return 0;}
Our My_atoh,my_hton is merged into the system function Inet_aton, and MY_NTOA is the system function Inet_ntoa.
#include <stdio.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h>int Main (int argc, char *argv[]) { char ip_buf[] = "180.97.33.107"; struct IN_ADDR my_addr; Inet_aton (IP_BUF,&MY_ADDR); printf ("IP:%s \ n", ip_buf); printf ("Net:%x \ n", my_addr.s_addr); return 0;}
Ip:180.97.33.107net:6b2161b4
Logically, the network byte order is the big-endian storage, should return 0xb461216b. actually called the system function Inet_aton, directly in the variable MY_ADDR.S_ADDR real memory space in the binary form to write the 0xb461216b (in fact, using bit operations, you can directly manipulate bits, the previous blog has a concrete implementation). The result is 0X6B2161B4 because our host is a small-end store, and the result with printf is to take the low byte first.
#include <stdio.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h>int Main (int argc, char *argv[]) { struct in_addr my_addr; My_addr.s_addr = 0xb461216b; printf ("Net:%x \ n", my_addr.s_addr); printf ("IP:%s \ n", Inet_ntoa (MY_ADDR)); return 0;}
net:b461216bip:107.33.97.180
Logically, the IP should output 180.97.33.107. In fact, the reason is very simple, our host is the small-end mode storage, and the network byte-order is the big-endian mode, when we assign 0xb461216b to my_addr.s_addr, in fact, the memory is 0x6b2161b4 in the form of storage, and inet_ The concrete implementation of the NTOA is directly manipulated by the bitwise operation BITS, so the result is naturally output 107.33.97.180.
Test the big end machine or the small terminal machine
#include <stdio.h> #include <stdlib.h>int main () { int a = 0x61;//97 printf ("%x\n", (char*) (&a) [0]);}
The result output 61, the description is the small end machine, first save low bytes.
System functions, whether Inet_aton or INET_NTOA, are implemented directly in the form of bitwise operations, so it is concerned with the actual binary storage of data in memory.
Use # To change the macro parameter to a string, using # #把两个宏参数贴合在一起.
The basic steps for TCP communication are as follows:
Server: Socket---BIND---listen---while (1) {---accept---recv---send---close---}------close
Client: Socket------------------------------Connect---Send---recv-----------------close
The basic steps for UDP communication are as follows:
Server: Socket---bind---recvfrom---sendto----close
Client: Socket----------sendto----recvfrom---Close
Tcp#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h > #include <unistd.h> #include <string.h> #include <stdio.h> #include <stdlib.h>server:int socket (int domain, int type, int protocol), int bind (int fd_server, struct sockaddr *addr_server, int addrlen); /* Bind the server contact, let the client have clear contact method can connect */int listen (int fd_server, int backlog); /* Convert Fd_server to passive socket, and the kernel will listen the requested contact into the queue */int accept (int fd_server, struct sockaddr *addr_client, int *addrlen); /* Return to the other end of the client socket to establish a connection *//* addr_client as an outgoing parameter that holds the contact information for the requesting connector, such as the need not to deliberately null */client:int connect (int fd_client,struct SOCKADDR *addr_server, int addrlen); /* Through the server contact Addr_server to connect to the server *//* as a server, must bind contact, otherwise the requester does not have a clear contact method can be connected, as a client, can not be bound contact, its port number will be automatically assigned by the system. The key to establishing the connection is that the Accept function returns a descriptor for the socket at the other end of the client socket descriptor, and the client's contact can also be obtained using the outgoing function in the accept. * * After connect:/* establishes the connection, you can use the socket descriptor to send the received message */int recv (int sockfd,void *buf,inT len,unsigned int flags);
int send (int s,const void * Msg,int len,unsigned int flags);
/* End of Session, close */int close (int fd);
Udpserver:int socket (int domain, int type, int protocol),/* Bind server contact, let client have clear contact method can connect */int bind (int fd_server, struct so CKADDR *addr_server, int addrlen); /* Since Fd_server has already bound contact (addr_server), the requestor sends the message via Addr_server to the server fd_server, so the server can receive the message via Fd_server, And the requester's contact can be obtained via outgoing parameter addr_client */int recvfrom (int fd_server, void *buf, int len, unsigned int flags, STRUC T sockaddr *addr_client, int *addrlen); /* The requestor's contact information (addr_client) is bound by the system itself, and the server gets addr_client through the recvfrom's outgoing parameters. Therefore, when the server sends a message, it can be sent to the client fd_client via client contact addr_client. */int sendto (int fd_server, const void *msg, int len, unsigned int flags, const struct SOCKADDR *addr_client, int addrlen) client:/* client contact, the server can be obtained at recvfrom, so it is not necessary to bind */int SendTo at the beginning (int fd_server, const void *msg, int len, unsigned int fla GS, const struct SOCKADDR *addr_client, int addrlen); int recvfrom (int fd_server, void *buf, int len, unsigned int flags, s Truct sockaddr *addr_client, int *addrlen); /* In fact, UTP Communication does not have a socket connection, and bothAre communicated by means of contact (IP and port number). The server needs to bind the contact at the beginning, otherwise the requester does not have a clear contact way to connect. When the server recvfrom, not only can receive the client's message, but also can obtain the client's contact information. */
1. TCP communication will establish a connection. The socket port of the server will bind the contact method, give the client a definite contact way to connect. The server listen to the client's connect and puts its contact information into the task request queue maintained by the kernel. After the server accept, get the corresponding socket port to communicate with the client, so as to establish the connection! The two sides then communicate through the socket port.
2. UDP communication does not establish a connection. The socket port of the server will also bind the contact method. The client sends a (SENDTO) message to the server through this contact, because this contact is bound to the server's socket port, so the server must be able to receive (RECVFROM) messages, at the same time through the outgoing parameters of Recvfrom to obtain the client's contact information, This allows messages to be sent to the client through the client's contact. That is, UTP communication is based on the contact method (IP and port number). is an unreliable means of communication.
3. Why is the accept and UDP recvfrom in TCP get contact information via outgoing parameters? If you don't understand it, you can send a letter by analogy, and when someone sends you a message, always write your own contact information.
Linux Network programming