This article aims to provide a quick start guide for beginners to quickly familiarize themselves with the C language.
Internet network applications. This document assumes that the reader has basic knowledge and syntax of C language and has experience in using Uinx/Linux. Although the socket programming in ubench/Linux is different from that in windows, I do not want to expand it here. In addition, all the programs in this article are compiled in Red Hat 5.2, and there are no problems in glibc 2.0.7 and libc 5.3.12 environments. Now let's start our tutorial :).
For a programmer, sockets is very similar to the underlying file descriptor (the read () and write () functions can be used in sockets), even though a socket ratio is set up to open, reading and writing a file is more troublesome, but this is because the network connection is much more complicated than reading and writing a local hard disk.
Usually, sockets is used to implement client/server pairs. The task of the server is to listen to a specific port and complete the corresponding service when receiving the service request from the client. The task of the client is to request the server to complete the preset service.
As an entry-level article, we will not use all socket types and functions here, but we will provide readers with sufficient information. Now, let's get started.
= + = + =
+ =
Create a socket: socket ()
The first thing you need to learn about socket programming is to use socket () to create a socket:
--------
# Include <sys/types. h>
# Include <sys/socket. h>
Int socket (int af, int type, int Protocol)
-------
'Int af' indicates the address family or the domain represented by socket. there are usually two options:
Af_unix-used only on a single machine.
Af_inet-communication can be performed on a single machine or other heterogeneous machines that use the DARPA protocol (UDP/TCP/IP.
'Int type' indicates the connection type you are using. There are two common cases:
Sock_stream-used to establish connection-oriented Sockets for reliable data transmission
Input
Sock_dgram-is used to establish a ETS without connection and cannot guarantee the reliability of data transmission.
In this article, we focus on using the af_inet address family and sock_stream connection types.
'Int Protocol' is usually set to 0. This aims to enable the system to select the default protocol determined by the protocol family and connection type.
The return value of this function is a file description handle. If an error occurs during this period,-1 is returned and the corresponding errno is set.
-------
# Include <sys/types. h>
# Include <sys/socket. h>
Int sockfd/* Soon to be socket file descriptor */
Sockfd = socket (af_inet, sock_stream, 0)
/* Error checking here */
-------
If the execution succeeds, we have a socket file handle, which can be used to access
Internet.
= + = + =
+ =
Name binding socket: BIND ()
The next step is to bind the name:
-------
# Include <sys/types. h>
# Include <sys/socket. h>
Int BIND (INT sockfd, struct sockaddr * Name, int namelen)
-------
In this function, sockfd is the file description handle obtained from the socket () call. Name is a point
A pointer to the sockaddr type structure. If the address family is set to af_unix, the definition of this type is
As follows:
-------
Struct sockaddr {
U_short sa_family;
Char sa_data [14];
};
-------
In this schema, name. sa_family should be set to af_unix. Name. sa_data should contain
A 14-byte file name, which is used to be allocated to the socket. Namelen provides
Length.
-------
# Include <sys/types. h>
# Include <SYS. Socket. h>
Struct sockaddr name;
Int sockfd;
Name. sa_family = af_unix;
Strcpy (name. sa_data, "/tmp/whatever ");
Sockfd = socket (af_unix, sock_stream, 0)
/* Error checking code here */
BIND (sockfd, & name, strlen (name. sa_data) + sizeof (name. sa_family)
/* Error checking code here */
-------
If the call is successful, the return value is 0. If the call fails, the return value is-1, and the corresponding error code errno is set.
Now, let's use another structure, which is used when the af_inet address family is used.
------
Struct sockaddr_in {
Short int sin_family;/* address family */
Unsigned short int sin_port;/* Port Number */
Struct in_addr sin_addr;/* Internet address */
Unsigned char sin_zero [8];/* same size as struct sockaddr */
};
-------
It seems that it is much larger than the previous one, but it is not very difficult to master it.
-------
# Include <stdio. h>
# Include <sys/types. h>
# Include <sys/socket. h>
# Include <errno. h>
Int sockfd, Port = 23;
Struct sockaddr_in my_addr;
If (sockfd = socket (af_inet, sock_stream, 0) =-1)
{
Printf ("socket error, % d \ n", errno );
Exit (1 );
}
My_addr.sin_family = af_inet;/* Host byte order */
My_addr.sin_port = htons (port);/* See man htons for more information
*/
My_addr.sin_addr.s_addr = htonl (inaddr_any);/* Get Our Address */
Bzero (& (my_addr.sin_zero), 8);/* zero out of the rest of the Space */
If (BIND (sockfd, (struct sockaddr *) & my_addr, sizeof (struct sockaddr ))
=-1)
{
Printf ("BIND error, % d \ n", errno );
Close (sockfd );
Exit (1 );
}
-------
Now, if there is no problem, the socket we created will have a name! On the contrary, if it fails, it will set the corresponding error code and exit the program. It should be noted that if your computer does not want to connect to other computers, there is no need to use bind (). Port binding is not suitable for servers. It should only be implemented on clients.
= + = + =
+ =
Remote connection: connect ()
This is a required step for connecting to other computers.
-------
# Include <sys/types. h>
# Include <sys/socket. h>
Int connect (INT sockfd, struct sockaddr * serv_addr, int addrlen );
-------
Sockfd is the file description handle we have created. serv_addr is a sockaddr structure that contains the target
Address and port number. addrlen is set to the size of the sockaddr structure.
-------
# Include <string. h>
# Include <sys/types. h>
# Include <sys/socket. h>
# Define dest_ip "132.241.5.10"
# Define dest_port 23
Main ()
{
Int sockfd;
Struct sockaddr_in dest_addr;/* will hold the destination ADDR */
Sockfd = socket (af_inet, sock_stream, 0);/* do some error checking! *
/
Dest_addr.sin_family = af_inet;/* Host byte order */
Dest_addr.sin_port = htons (dest_port);/* short, network byte order */
Dest_addr.sin_addr.s_addr = inet_addr (dest_ip );
Bzero (& (dest_addr.sin_zero), 8);/* zero the rest of the struct */
Connect (sockfd, (struct sockaddr *) & dest_addr, sizeof (struct sockaddr)
);
/* Error checking code here */
/* More code
.
.
.
*/
}
-------
Similarly, after the return value of Connect () is called, if the return value is 0, it indicates success. If the return value is 1, it indicates that there is an error and the corresponding error code is set. Since we don't care about the specific port connection, we didn't call the BIND () function in the above routine.
= + = + =
+ =
Listener: Listen ()
When we need to create a server, we need a means to listen to input requests, while
The listen () function provides this function.
-------
# Include <sys/types. h>
# Include <sys/socket. h>
Int listen (INT sockfd, int backlog );
-------
The backlog parameter indicates the number of connections that can be monitored at a time.
The returned results of its call are the same as those of the preceding functions.
It is worth mentioning that here we need to establish a binding to receive service requests from specific ports.
-------
Socket ();/* to create out socket file descriptor */
BIND ();/* to give our socket a name */
Listen ();/* listen for connection */
-------
= + = + =
+ =
Accept connection: accept ()
Now, let's start substantive work. When someone tries to log in from the opened port, we should respond to it. This requires the accept () function.
-------
# Include <sys/types. h>
# Include <sys/socket. h>
Int accept (INT sockfd, void * ADDR, int * addrlen );
-------
The parameters required for function calling are all familiar to us :)
-------
# Include <string. h>
# Include <sys/types. h>
# Include <sys/socket. h>
# Define myport 1500/* The port users will be ing */
# Define backlog 5/* how to handle pending connections queue will hold */
Main ()
{
Int sockfd, new_fd;/* listen on sock_fd, new connection on new_fd */
Struct sockaddr_in my_addr;/* My address information */
Struct sockaddr_in their_addr;/* connector's address information */
Int sin_size;
Sockfd = socket (af_inet, sock_stream, 0);/* do some error checking! *
/
My_addr.sin_family = af_inet;/* Host byte order */
My_addr.sin_port = htons (myport);/* short, network byte order */
My_addr.sin_addr.s_addr = inaddr_any;/* auto-fill with my IP */
Bzero (& (my_addr.sin_zero), 8);/* zero the rest of the struct */
/* Did you remember your error checking? */
BIND (sockfd, (struct sockaddr *) & my_addr, sizeof (struct sockaddr ));
Listen (sockfd, backlog );
Sin_size = sizeof (struct sockaddr_in );
New_fd = accept (sockfd, & their_addr, & sin_size );
-------
Here we should note that we use new_fd to complete all the receiving and sending operations. If there is only one connection, you can disable the original sockfd to prevent more input requests.
= + = + =
+ =
Input and input completion: Send () and Recv ()
After we have completed the above work, the last step is to transmit data :). Here, we use send () and Recv.
-------
# Include <sys/types. h>
# Include <sys/socket. h>
Int send (INT sockfd, const void * MSG, int Len, int flags );
Int Recv (INT sockfd, void * Buf, int Len, unsigned int flags );
-------
Send ():
Sockfd-socket file descriptor
MSG-message to send
Len-size of message to send
Flags-read 'man send' for more info, set it to 0 for now
Recv ():
Sockfd-socket file descriptor
Buf-data to receive
Len-size of BUF
Flags-same as flags in send ()
Send () routine:
-------
Char * MSG = "Hey there people ";
Int Len, send_msg;
/* Code to create (), BIND (), listen () and accept ()*/
Len = strlen (MSG );
Bytes_sent = Send (sockfd, MSG, Len, 0 );
-------
Recv () routine:
-------
Char * Buf;
Int Len, recv_msg;
/* Code to create (), BIND (), listen () and accept ()*/
Len = strlen (BUF );
Recv_msg = Recv (sockfd, Buf, Len, 0 );
-------
If your connection type is sock_dgram, use sendto () and recvfrom () for data transmission.
= + = + =
+ =
Last step: Close () and Shutdown ()
When the transfer ends, the connection should be closed.
-------
# Include <stdio. h>
/* All you code */
Close (sockfd );
-------
The more insurance method is to use Shutdown () to close the connection.
-------
Int Shutdown (INT sockfd, int how)
-------
Select the parameter "how:
1-cannot receive more data
2-more data cannot be sent.
3-you cannot receive or send more data (the same as close)
Everything is so simple :)
= + = + =
+ =
Who are you: getpeerbyname ()
You may want to know who is connecting to you:
-------
# Include <sys/socket. h>
Int getpeername (INT sockfd, struct sockaddr * ADDR, int * addrlen );
-------
The ADDR parameter is a pointer to 'struct sockadd' or 'struct sockaddr_in.
If the execution succeeds, we get the address of the other party, and then use inet_ntoa () to use gethostbyad
Dr () to get more information from the other party. For more information, see RFC 1413.
= + = + =
+ =
Who am I: gethostname ()
-------
# Include <unistd. h>
Int gethostname (char * hostname, size_t size );
-------
Hostname is an array of characters that store host names.
The returned hostname can be used as the parameter of gethostbyname (), so that you can obtain your own IP address.
= + = + =
+ =
What is my IP address?
Now we can concentrate on what we have learned and gradually complete a practical program. Let's take a look at the following situations:
$ Telnet Microsoft.com
Trying 206.163.24.176 (not the real address but I'm too lazy to try
)
We can see that the first thing the telnet program does is domain name resolution! This task is completed by gethostbyname.
-------
# Include <netdb. h>
Struct hostent * gethostbyname (const char * Name );
-------
A special hostent structure:
-------
Struct hostent {
Char * h_name;
Char ** h_aliases;
Int h_addrtype;
Int h_length;
Char ** h_addr_list;
};
# Define h_addr h_addr_list [0]
-------
This structure can be divided:
H_name-formal machine name
H_aliases-a string ending with null, indicating the machine alias.
H_addrtype-the type used by the address, usually af_inet.
H_length-The address length expressed by the number of nodes.
H_addr_list-an array ending with 0, indicating the network address of the machine, which is arranged in bytes of the network.
H_addr-the first address in h_addr_list.
Gethostbyname () returns a pointer to the hostent structure or a null pointer to indicate an error (however, the error code is not set !).
Now let's complete our DNS program:
-------
# Include <stdio. h>
# Include <stdlib. h>
# Include <errno. h>
# Include <netdb. h>
# Include <sys/types. h>
# Include <netinet/in. h>
Int main (INT argc, char * argv [])
{
Struct hostent * h;
If (argc! = 2) {/* error checking on the command line */
Fprintf (stderr, "Usage: getip <Host Name> \ n ");
Exit (1 );
}
If (H = gethostbyname (argv [1]) = NULL) {/* Get the host info */
Herror ("gethostbyname ");
Exit (1 );
}
Printf ("Host Name: % s \ n", H-> h_name );
Printf ("IP Address: % s \ n", inet_ntoa (* (struct in_addr *) H-> h_addr )));
Return 0;
}
-------
You can use gcc-O getip. C.
= + = + =
+ =
Client and server programs
Let's end this article with a small client-server application.
The purpose of this applet is to connect a user to the server, receive pre-defined data, and then disconnect. However, there are many errors in this program that need to be modified and completed as your job :).
-------
<++> Socket/server. c
/* Server program */
# Include <stdio. h>
# Include <stdlib. h>
# Include <errno. h>
# Include <string. h>
# Include <sys/types. h>
# Include <netinet/in. h>
# Include <sys/socket. h>
# Include <sys/Wait. H>
# Define port 1500/* The port users will be ing */
# Define backlog 5/* how to handle pending connections queue will hold */
Main ()
{
Int sockfd, new_fd;/* listen on sock_fd, new connection on new_fd */
Struct sockaddr_in my_addr;/* our address information */
Struct sockaddr_in their_addr;/* their address information */
Int sin_size;
Sockfd = socket (af_inet, sock_stream, 0 );
/* Remember to error check (-1 on error )*/
My_addr.sin_family = af_inet;/* Host byte order */
My_addr.sin_port = htons (port);/* short, network byte order */
My_addr.sin_addr.s_addr = inaddr_any;/* auto-fill with my IP */
Bzero (& (my_addr.sin_zero), 8);/* zero the rest of the struct */
BIND (sockfd, (struct sockaddr *) & my_addr, sizeof (struct sockaddr ));
Listen (sockfd, backlog)
While (1) {/* start out accept () loop */
Sin_size = sizeof (struct sockaddr_in );
New_fd = accept (sockfd, (struct sockaddr *) & their_addr, & sin_size)
Printf ("server: Got connection from % s \ n", inet_ntoa (their_addr.sin_ad
Dr ));
Fork ();/* this is the child process */
Send (new_fd, "Hello, world! \ N ", 14, 0)
Close (new_fd );
Exit (0 );
While (waitpid (-1, null, wnohang)> 0);/* clean up child processes */
}
}
/* End server program, remember to do your error checking */
<-->
<++> Socket/client. c
/* Client Program */
# Include <stdio. h>
# Include <stdlib. h>
# Include <errno. h>
# Include <string. h>
# Include <netdb. h>
# Include <sys/types. h>
# Include <netinet/in. h>
# Include <sys/socket. h>
# Define port 1500/* The port client will be connecting */
# Define maxdatasize 100/* max number of bytes we can get at once */
Int main (INT argc, char * argv [])
{
Int sockfd, numbytes;
Char Buf [maxdatasize];
Struct hostent * He;
Struct sockaddr_in their_addr;/* connector's address information */
If (argc! = 2 ){
Fprintf (stderr, "Usage: client <Host Name> \ n ");
Exit (1 );
}
He = gethostbyname (argv [1]);/* Get the host info */
/* Did you check for errors? */
Sockfd = socket (af_inet, sock_stream, 0 );
Their_addr.sin_family = af_inet;/* Host byte order */
Their_addr.sin_port = htons (port);/* short, network byte order */
Their_addr.sin_addr = * (struct in_addr *) He-> h_addr );
Bzero (& (their_addr.sin_zero), 8);/* zero the rest of the struct */
Connect (sockfd, (struct sockaddr *) & their_addr, sizeof (struct sockaddr
));
Numbytes = Recv (sockfd, Buf, maxdatasize, 0 );
Buf [numbytes] = '\ 0 ';
Printf ("Received: % s", Buf );
Close (sockfd );
Return 0;
}
/* End client... you checked for errors right? */
<-->