Parsing C language key points for socket programming based on UDP protocol _c language

Source: Internet
Author: User
Tags error handling prepare string format strlen port number htons

Two Protocols TCP and UDP
The former can be understood as a guaranteed connection, and the latter is the pursuit of fast connections.
Of course, the last point is a bit too absolute, but now do not have to boil too much, because the first socket programming, basics.
A little imagine can be roughly understood, TCP is the pursuit of reliable transmission of data, UDP is the pursuit of fast data transmission.
The former has a cumbersome connection process, while the latter is simply not establishing a reliable connection (not absolute), but sending the data without considering whether or not to arrive.
The following example takes the *nix platform as an example, because the Windows platform needs to consider additional loading issues, and a few additions can run UDP on the Windows platform.

Udp

This is a very simple connection, assuming that there are two hosts to communicate, one to send only, one only receive.
Receiving end:

  int sock; /* Socket/*
  socklen_t Addr_len/* The address length of the sender, for recvfrom
  /char mess[15];
  Char Get_mess[get_max]; * Later version
  of the use of * * struct sockaddr_in recv_host, send_host;

  * * Create socket
  /sock = socket (pf_inet, SOCK_DGRAM, 0);

  * * To bind the IP and port number information on the socket
  /memset (&recv_host, 0, sizeof (recv_host));
  recv_host.sin_family = af_inet;
  RECV_HOST.SIN_ADDR.S_ADDR = htonl (inaddr_any);/* Receive any IP/
  recv_host.sin_port = htons (6000);/* Use 6000 port number */
  bind (sock, (struct sockaddr *) &recv_host, sizeof (Recv_host));

  /* Enter the status of receiving information * *
  recvfrom (sock, mess, 0, (struct sockaddr *) &send_host, &addr_len);

  /* receive complete, closed socket/close
  (sock);

The code above omits many of the necessary error checks to be added when you actually write

Code Explanation:
Pf_inet represents the type of protocol, which represents the IPV4 network protocol family, and the same PF_INET6 represents the IPV6 network protocol family, which is recorded separately in the rear and not mixed with IPv4 (does not mean more complex, actually simpler). The
Af_inet represents the type of address, which represents the address family used by the IPV4 network protocol, as well as the Af_inet6 (Pf_inet and af_inet values in the operating system implementation, but it is better to write macros than to use numbers or confuse them directly)
H The use of tonl and htons two functions involves big-end small-ended problems, which are not described here, and it is important to remember to use this function to turn the necessary information into a terminal notation in network programming.
(struct sockaddr *) This cast is required for parameters, but not error, because sizeof (struct sockaddr_in) = = sizeof (struct sockaddr) can specifically query the relevant information, The reason for this is to facilitate programmers who write socket programs.
Send end:

  int sock;
  Const char* mess = "Hello server!";
  Char Get_mess[get_max]; * Later version of the use of * *
  struct sockaddr_in recv_host;
  Socklen_t Addr_len;
  * * Create socket
  /sock = socket (pf_inet, SOCK_DGRAM, 0);
  /* Binding *
  /memset (&recv_host, 0, sizeof (recv_host));
  recv_host.sin_family = af_inet;
  RECV_HOST.SIN_ADDR.S_ADDR = inet_addr ("127.0.0.1");
  Recv_host.sin_port = htons (6000);
  /* Send information/
  * Here, the sender's IP address and port number and other types of information, with this function of the call, automatically bound on the socket
  /sendto (sock, mess, strlen (mess), 0, (struct SOCKADDR *) &recv_host, sizeof (Recv_host));
  /* completed, closed
  /close (sock);

The above code is the sender side.

Code Explanation:
The INET_ADDR function is an address type that converts an IP address in a string format to a big-endian notation, that is, the type of s_addr in_addr_t
In contrast to the same function Inet_ntoa is used to in_addr The _t type is converted to a string, but be sure to remember to copy the return value Char addr[16] in time. RECV_HOST.SIN_ADDR.S_ADDR = inet_addr ("127.0.0.1"); strcpy (addr, Inet_ntoa (RECV_HOST.SIN_ADDR.S_ADDR));
from the above code, the use of UDP protocol is very concise, almost is to create socket-> prepare data-> equipment Socket-> Send/Receive-> end
which, there is no connection operation, but in fact this is to facilitate UDP at any time and different host The default setting for communication, if you need to communicate with the same host all the time?
The original in this case does not need to know, logging method, that is, long time to use UDP and the same host communication, you can use the Connect function to optimize itself. This assumes that the actual functionality of the two hosts is consistent and that both receive and send the
Send end:

  /* Front is highly consistent, replace the BIND function with
  /connect (sock, (struct sockaddr *) &recv_host, sizeof (recv_host);//Register each other's IP address and port number in UD P's socket) while
  (1)/* loop Sending and receiving information * *
   size_t read_len = 0;
   /* Original use of the SendTo function, the first choice to use the Write function, Windows platform for the Send function
   /write (sock, mess, strlen (mess));      /* Send (sock, mess, strlen (mess), 0) for Windows Platform *
   /Read_len = Read (sock, get_mess, get_max-1);/* RECV (sock, Mess, strlen (mess)-1, 0) for Windows Platform * * * *
   get_mess[read_len-1] = ';
   printf ("In-Client like host recvive from other Host:%s\n", get_mess);
  }
  /* Rear height consistent * *

Receiving end:

 * * Front consistent, add extra struct sockaddr_in send_host; and add loops, construct the phenomenon of sending and receiving * * while (1) {size_t
   Read_len = 0; Char sent_mess[15] = "Hello sender!";
   /* The information used for sending/* sendto (sock, Mess, strlen (sent_mess), 0, (struct sockaddr *) &recv_host, sizeof (recv_host));
   Read_len = recvfrom (sock, mess, 0, (struct sockaddr *) &send_host, &addr_len) mess[read_len-1] = ';
  printf ("In Sever-like host recvive:%s\n", mess); }/* Rear height consistent/* * The reason why we use connect only on the receiving end is that we simulate the client-server model, and the server's information is not arbitrarily changed * but the client is different, possibly because of the ISP (Internet
  Server Provider), your IP address can not always be fixed, so only * to ensure that the client part of the server to register the various types of information, and can not register the client information on the server side.
  * And of course there are exceptions, for example, you want this software as a private software, only for two people to use, and you have a fixed IP address, then you can connect on both sides, but * must note that as long as a little information changes, the software may not be able to send and receive information properly. */

Code explanation
As a matter of fact, although the table ahead shows that UDP does not seem to be necessary for connect, it is actually a useful place to use.
As far as the *nix API is concerned, the difference between sendto and write is obvious, which is a variety of information that needs to be supplied to the target host in the parameters, while the latter does not need to be provided. The same is true of recvfrom and read.
This code is just a demo, so put the code in an infinite loop, in reality you can define the export conditions.
The above is a few simple description of UDP, Getting started is enough, not detailed description of the specific use of some functions, but with practical examples to reflect. Before you record TCP, you still need to speak a function shutdown
shutdown and Close (closesocket)

First of all, you know, network communication is generally the joint between the two sides, in other words is two-way, One direction is used only to send messages, One direction is used only to read messages.
This leads to the need to turn off the two-directional channels (called their channels) at the end of the socket communication, and is it not possible to close at the same time? I can do that.
Close (sock); Closesocket (sock); For Windows PlatForm is doing this, disconnecting two of directions at the same time.
Simple communication program or one-way communication program it does not matter, but what if you need to receive the last message at the end of the communication?
Assuming the communication is over, the client sends "Thank you" to the server
The server needs to receive this information before it can turn off traffic
The problem is that the server doesn't know what the client is going to hear at the end of the communication.
So we choose to shut down the server's send channel (write stream) after the communication completes, wait for the client to send the message, close the remaining receive channel (read stream)
Send end:

  /* Assume that there is a TCP connection, this is the client
  /write (sock, "Thank You", ten);
  Close (sock); Close the communication directly after writing

Receiving end:

  * * This is the server
  ///////* First close Write flow/shutdown (Sock_c, SHUT_WR);
  Read (Sock_c, get_mess, Get_max);
  printf ("Message:%s\n", get_mess);
  Close (Sock_c);
  Close (sock_s); Shutting down two sockets is due to the needs of the TCP server side, which records

Code explanation
The role of the shutdown function is to selectively turn off the output in that direction.

int shutdown (int sock, int howto);

Sock represents the socket to be manipulated
Howto has several options.

    • * NIX * *: shut_rd SHUT_WR Shut_rdwr
    • Windows:sd_receive Sd_send Sd_both


Below, there are several structures, and an interface is very important and common:

    • struct SOCKADDR_IN6: Represents the address information of IPV6
    • struct Addrinfo: This is a generic structure that can store information about IPV4 or IPV6 type addresses
    • Getaddrinfo: This is a very convenient interface, in the above UDP program many manual filling parts, can be omitted, there is this function for us to complete

Rewrite The example above:

Receiving end:

  int sock; * * Socket/socklen_t Addr_len;
  /* The address length of the sender, for recvfrom * * Char mess[15]; Char Get_mess[get_max]; * Later version of the use of * * struct sockaddr_in host_v4; /* IPV4 Address * * struct SOCKADDR_IN6 host_v6; /* IPV6 Address * * struct addrinfo easy_to_use;  /* Used to set the information to obtain and how to obtain information * * struct addrinfo *result;

  /* used to store the resulting information (pay attention to memory leaks)/struct addrinfo * p;
  * * Prepare information/memset (&easy_to_use, 0, sizeof easy_to_use); easy_to_use.ai_family = Af_unspec; /* Tell the interface, I do not yet know the address type * * Easy_to_use.ai_flags = ai_passive; /* Tell the interface, later "You" to help me fill out I did not explicitly specify the information * * Easy_to_use.ai_socktype = SOCK_DGRAM;
  /* Argv[1] in the string form of the port number * * * * * Create sockets, there will be two ways of writing, but more insurance, reliable writing is so//////* Legacy method * sock = socket (pf_inet, SOCK_DGRAM, 0);
  * * * To bind IP and port number information on sockets///////////* memset (&recv_host, 0, sizeof (recv_host));
  * recv_host.sin_family = af_inet; * recv_host.sin_addr.s_addr = htonl (Inaddr_any);* Receive any IP/* recv_host.sin_port = htons (6000);
  * * Use 6000 port number/* BIND (sock, (struct sockaddr *) &recv_host, sizeof (recv_host)); * (p = result P!= NULL; p = p->ai_next)/* This syntax needs to open the-STD=GNU99 standard/{sock = socket (p->ai_family, P-&G
    T;ai_socktype, P->ai_protocol);
    if (sock = = 1) continue;
     if (Bind (sock, p->ai_addr, p->ai_addrlen) = = 1) {close (sock);
    Continue } break; /* If you can execute to this, prove that the socket success, socket binding success, so no need to try again.
  * * * Enter the status of receiving information * *//recvfrom (sock, mess, 0, (struct sockaddr *) &send_host, &addr_len);
    Switch (p->ai_socktype) {case af_inet:addr_len = sizeof host_v4;
    Recvfrom (sock, mess, 0, (struct sockaddr *) &host_v4, &addr_len);
    Break Case Af_inet6:addr_len = sizeof host_v6 recvfrom (sock, mess, 0, (struct sockaddr *) &host_v6, &addr_
     Len);
    Break
  Default:break; } freeaddrinfo (Result); /* Free this space, by getaddrinfo assigned/////////* Receive complete,Turn off socket/close (sock);

 

Code Explanation:

First, explain a few new structures.

struct Addrinfo The internal order of this structure is slightly different for *nix and Windows, for example *nix

 struct addrinfo{
  int ai_flags;
  int ai_family;
  int ai_socktype;
  int ai_protocol;
  Socklen_t Ai_addrlen;
  struct sockaddr * AI_ADDR; /* Place the result address
  /char * ai_canonname;/* ignore it, for a long time you don't have to pay attention to it *
  * struct addrinfo * ai_next;/* A domain/IP address may resolve multiple different IPs */
 };

ai_family If you set it to Af_unspec then when you call Getaddrinfo, it automatically helps you determine what type of address is passed in.
Ai_flags if it is set to Ai_passive, then calling Getaddrinfo and passing in NULL to its first argument automatically binds its own IP, which is equivalent to setting Inaddr_any

    • Ai_socktype is the type of socket you want to create, this must be explicitly stated that the system can not be predefined (artificial intelligence in the future?)
    • Ai_protocol normally we set to 0, meaning we can find it by ourselves, such as MSDN or UNP
    • AI_ADDR Here The result is saved, which can be obtained by invoking the fourth argument after getaddrinfo.
    • Ai_addrlen ditto
    • Ai_next ditto

Getaddrinfo Powerful interface functions

int getaddrinfo (const char * node, const char * service,
const struct Addrinfo * hints, struct addrinfo * res);
In layman's parlance, the role of these parameters
node is to be acquired or to be bound by the domain name or IP, that is, this can be directly filled out the domain name, by the operating system to convert to IP information, or directly fill in the IP can also be the form of a string
Service is the meaning of the port number, but also the string form
Hints is to tell the interface, I need you to feedback what information to me (the fourth parameter), and fill this information into the fourth parameter.
Res is where the results are saved, and it should be noted that this result is dynamically allocating memory inside the API, so you need to invoke another interface (Freeaddrinfo) to release it after use
In fact, for modern socket programming, there are several new structures for storing IP information, such as struct sockaddr_in6 and struct sockaddr_storage.

Where the former is a subset of the size of the latter, that is, a struct storage must be able to install a struct sockaddr_in6, specific (actually do not see a meaningful implementation)

  struct sockaddr_in6{
   u_int16_t sin6_family;
   u_int16_t Sin6_port;
   u_int32_t Sin6_flowinfo; * * Temporarily ignore it/
   struct IN6_ADDR sin6_addr/* IPv6 address stored in this structure/
   u_int32_t sin_scope_id; * Temporarily ignore it * *
  ;
  struct in6_addr{
   unsigned char s6_addr[16];
  }
  ------------------------------------------------------------
  struct sockaddr_storage{
   sa_family_t ss_ Family /* Address type
   /char __ss_pad1[_ss_pad1size];/* Starting from here, is not the implementation of almost no way to understand * * *
   int64_t __ss_align;      /* from the name can be seen to be compatible with two different IP types of compromise
   /char __ss_pad2[_ss_pad2size];/* Hidden the actual content, in addition to the type of IP, can not directly obtain any other information. * *
   * in the implementation of various *nix, may have different implementations, such as ' __ss_pad1 ', ' __ss_pad2 ', may be merged into a ' pad '. */
  };

In practice, we often do not need to declare different types of storage for different IP types, direct use of struct sockaddr_storage can be, when used directly cast type can be

Rewrite the upper receiver example to enter the state part of the receiving information

  /////////
  -struct sockaddr_in host_v4///-IPV4 address///struct SOCKADDR_IN6-host_v6
  ;/* IPV6 address
  s Truct Sockaddr_storage Host_ver_any; /* + any type of IP address * ...
  /* Enter the state part of receiving information * *
  recvfrom (sock, mess, 0, (struct sockaddr *) &host_ver_any, &addr_len);/* like, back to the IPv4. ERA */

Complete the corresponding send end code above

  int sock;
  Const char* mess = "Hello server!"; Char Get_mess[get_max]; * Later version of the use of * * struct sockaddr_storage recv_host; /*-struct sockaddr_in recv_host;
  * * struct addrinfo tmp, *result;
  struct Addrinfo *p;

  Socklen_t Addr_len;
  /* Get the information on the end/memset (&tmp, 0, sizeof TMP);
  tmp.ai_family = Af_unspec;
  Tmp.ai_flags = ai_passive;
  Tmp.ai_socktype = Sock_dgram; Getaddrinfo (Argv[1], argv[2], &tmp, &result); /* Argv[1] represents the IP address on the end, Argv[2] on behalf of the port number on the end/* Create socket/* (p = result; p!= NULL; p = p->ai_next) {sock = s Ocket (p->ai_family, P->ai_socktype, P->ai_protocol); /*-sock = socket (pf_inet, SOCK_DGRAM, 0);
   */if (sock = 1) continue; /* There is less binding to bind functions, as the sender does not need to have the End-to-end information bound to the created socket. * * BREAK; /* Find can exit, of course, may not be found, then the value of P must be null/} if (P = = null) {/* error handling/}/*-//set the End-to-end information memset (&recv_ho
  St, 0, sizeof (recv_host));
  recv_host.sin_family = af_inet; RECV_HOST.SIN_ADDR.S_ADDR = inet_addr ("127.0.0.1");
  Recv_host.sin_port = htons (6000); * * * Send the message/* Here, the sender's IP address and port number and other types of information, with this function of the call, automatically bound on the socket/sendto (sock, mess, strlen (mess), 0, P->AI_ADDR, p
  ->ai_addrlen); /* complete, close/freeaddrinfo (result);        

 /* In fact, this function should be called at the place where result is used/close (sock);

Here, in fact, is the beginning of a network programming, lifting the modern UDP the simplest use (not even a complete usage), but it is really interactive.
The introduction of UDP is not because it is simple, but because he is concise, nor because it is not important, on the contrary, he is actually very strong.
Never underestimate a simple thing, just like C language

ARP protocol

The easiest way is to find a WireShark software or tcpdump of the *nix platform, the former you can choose to listen to a machine at will, not long to see the use of the ARP protocol, because it used too often.
For the ARP protocol, first for a machine A, want to communicate with machine B, (assuming that the cache area of machine A (the operating system is updated at some time) does not have machine B's caching),
Then machine A will send an ARP request to the broadcast address, if machine B receives this request, then fills its own information (IP address, MAC address) into the ARP reply, then sends back on the line.
In the above, ARP request and ARP reply is a message form information, it is the implementation product that the ARP protocol comes with, it is also used for communication between two hosts.
This is when machine A and machine B are in the same network, you can use the broadcast address of this network segment to send the request message.
For different network segments of machine A and machine B, want to get the MAC address through the ARP protocol, you need to use the help of the router, you can imagine that the router (can more than one) in the middle, machine A and machine B on both sides of these routers (that is, in different subnets)
Because A and B are not in the same subnet, so there is no way through directly through the broadcast, but with the router, you can do the ARP proxy operation, presumably is the router as a machine B, a to their local router to send ARP request
After the router to determine is sent to B ARP request, and just b in their own jurisdiction, put their hardware address into the ARP answer sent back, and then have a to B data, is a first sent to the router, and then through the router sent to B

ICMP protocol

This protocol is more important. The
requests the reply message and the error message, the emphasis is the error message. The
request answering message can be used in ICMP to query information such as the subnet mask of this computer. Roughly by sending the request message to all the hosts in the web (including themselves, in fact, broadcasting), receiving the reply and getting the information
error message will be mentioned in the follow-up, there is a need for popular science one or two.
First of all, a large part of the error message is about the type of XXX that cannot be reached, for example, host unreachable, Port unreachable, and so on, every time there is an error, the ICMP message is always the first time to return to the end, (it will only appear one at a time, otherwise it will create a network storm), but the end is able to receive, It's not a problem with the sending side.
This type of socket has some connection, for example, UDP ignores ICMP packets in the unconnected state. TCP is very good at capturing ICMP packets because it is always connected.
ICMP error messages are always paired with a portion of the real data in an error datagram.

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.