[Collection] in simple and simple "network socket Programming Guide" __ Programming

Source: Internet
Author: User
Tags data structures microsecond timer socket blocking stdin htons
Typically, there is only one server on the service side, which employs fork () to handle connections from multiple customers. The basic program is that the server waits for a connection, accepts (accept ()) the connection, and then fork () a subprocess processes it. This is the next chapter in our example.
--------------------------------------------------------------------------------
A simple server
All the work done by this server is to send a string "Hello, world!/n" on the streaming connection. To test this program, you can run the program on a single machine and log on to another machine:
$ telnet Remotehostname 3490
Remotehostname is the name of the machine that the program runs on.
Server code:
#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 MYPORT 3490/* Define user connection Port * *
#define BACKLOG 10/* How many wait for connection control * *
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;
if ((SOCKFD = socket (af_inet, sock_stream, 0)) = = 1) {
Perror ("socket");
Exit (1);
}

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),;/* Zero the rest of the struct * *

if (bind (SOCKFD, struct sockaddr *) &my_addr, sizeof (struct
SOCKADDR) = = = 1) {
Perror ("bind");
Exit (1);
}
if (Listen (SOCKFD, BACKLOG) = = 1) {
Perror ("Listen");
Exit (1);
}

while (1) {/* main accept () loop */
sin_size = sizeof (struct sockaddr_in);
if (new_fd = Accept (SOCKFD, (struct sockaddr *) &their_addr,/
&sin_size) = = = 1) {
Perror ("accept");
Continue
}
printf ("Server:got connection from%s/n",/
Inet_ntoa (THEIR_ADDR.SIN_ADDR));
if (!fork ()) {/* This is the child process * *
if (Send (NEW_FD, "Hello, world!/n", 14, 0) = = 1)
Perror ("send");
Close (NEW_FD);
Exit (0);
}
Close (NEW_FD); /* Parent doesn ' t need this * * *
while (Waitpid ( -1,null,wnohang) > 0); /* Clean up child processes * *
}
}
If you're picky, you'll be unhappy with me. All of the code is in a large main () function. If you don't like it, you can divide it into finer points.
--------------------------------------------------------------------------------------------------------------- --------------

Simple client program
This program is simpler than the server. All the work of this program is to connect to the host specified on the command line via port 3490 and then get the string sent by the server.
Customer Code:
#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 3490/* Client connection to the remote host
#define MAXDATASIZE 100/* Maximum bytes can be received each time * *
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 hostname/n");
Exit (1);
}
if ((He=gethostbyname (argv[1)) = = NULL) {/* Get the Host info */
Herror ("gethostbyname");
Exit (1);
}

if ((SOCKFD = socket (af_inet, sock_stream, 0)) = = 1) {
Perror ("socket");
Exit (1);
}

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),;/* Zero the rest of the struct * *
if (Connect (SOCKFD, struct sockaddr *) &their_addr,sizeof (struct
SOCKADDR) = = = 1) {
Perror ("Connect");
Exit (1);
}
if ((Numbytes=recv (SOCKFD, buf, maxdatasize, 0)) = = 1) {
Perror ("recv");
Exit (1);
}
Buf[numbytes] = '/0 ';
printf ("Received:%s", buf);
Close (SOCKFD);
return 0;
}
Note that if you run the client program before running the server, connect () will return "Connection refused" information, which is useful.
--------------------------------------------------------------------------------------------------------------- ---------

Data Packet Sockets
I don't want to say any more, so I give the code TALKER.C and LISTENER.C.
Listener a packet waiting on the machine to 4590来 on the port. Talker sends packets to a certain machine that contains what the user enters at the command line.
This is listener.c:
#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 MYPORT 4950/* The port users would be sending to/*
#define Maxbuflen 100
Main ()
{
int sockfd;
struct sockaddr_in my_addr; /* My Address information * *
struct sockaddr_in their_addr; /* connector ' s address information * *
int Addr_len, numbytes;
Char Buf[maxbuflen];
if ((SOCKFD = socket (af_inet, SOCK_DGRAM, 0)) = = 1) {
Perror ("socket");
Exit (1);
}
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),;/* Zero the rest of the struct * *
if (bind (SOCKFD, struct sockaddr *) &my_addr, sizeof (struct sockaddr))
/
= =-1) {
Perror ("bind");
Exit (1);
}
Addr_len = sizeof (struct sockaddr);
if (Numbytes=recvfrom (SOCKFD, buf, Maxbuflen, 0,/
(struct sockaddr *) &their_addr, &addr_len)) = =-1) {
Perror ("Recvfrom");
Exit (1);
}
printf ("Got packet from%s/n", Inet_ntoa (THEIR_ADDR.SIN_ADDR));
printf ("Packet is%d bytes long/n", numbytes);
Buf[numbytes] = '/0 ';
printf ("Packet contains/"%s/"/n", buf);
Close (SOCKFD);
}
Note that in our call to the socket (), we end up using the Sock_dgram. At the same time, there is no need to use listen () or accept (). We are using connectionless datagram sockets.
Here is talker.c:
#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 MYPORT 4950/* The port users would be sending to/*
int main (int argc, char *argv[])
{
int sockfd;
struct sockaddr_in their_addr; /* connector ' s address information * *
struct Hostent *he;
int numbytes;

if (argc!= 3) {
fprintf (stderr, "usage:talker hostname message/n");
Exit (1);
}

if ((He=gethostbyname (argv[1)) = = NULL) {/* Get the Host info */
Herror ("gethostbyname");
Exit (1);
}

if ((SOCKFD = socket (af_inet, SOCK_DGRAM, 0)) = = 1) {
Perror ("socket");
Exit (1);
}

their_addr.sin_family = af_inet; /* Host byte order * *
Their_addr.sin_port = htons (MyPort); /* short, network byte
*/
their_addr.sin_addr = * (struct in_addr *) he->h_addr);
Bzero (& Their_addr.sin_zero),;/* Zero the rest of the struct * *
if (Numbytes=sendto (SOCKFD, argv[2], strlen (argv[2)), 0,/
(struct sockaddr *) &their_addr, sizeof (struct sockaddr))) = = = 1) {
Perror ("SendTo");
Exit (1);
}
printf ("sent%d bytes to
%s/n ", Numbytes,inet_ntoa (THEIR_ADDR.SIN_ADDR));
Close (SOCKFD);
return 0;
}
That's all that's out there. Run listener on one machine, then run talker on another machine. Observe their communications.
In addition to some small details of the data socket connections I mentioned above, for data sockets, I have to say that when a speaker calls the Connect () function and assigns the recipient's address, it can be seen from this point that the speaker can only send and receive information to the address specified by the Connect () function. Therefore, you do not need to use sendto () and Recvfrom (), and you can replace it with Send () and recv ().
--------------------------------------------------------------------------------
Blocking
Obstruction, you may have heard it long ago. "Blocking" is the technical jargon of "sleep". You may notice the listener program running in front of you, where it runs continuously, waiting for the packet to arrive. The actual running is that it calls Recvfrom (), and then there is no data, so recvfrom () says "block" until the data arrives.
Many functions use blocking. Accept () block, all recv* () functions are blocked. They are able to do so because they are allowed to do so. When you first call socket () to establish a socket descriptor, the kernel sets it to block. If you do not want socket blocking, you will call the function fcntl ():
#include <unistd.h>
#include <fontl.h>
.
.
SOCKFD = socket (af_inet, sock_stream, 0);
Fcntl (SOCKFD, F_SETFL, O_nonblock);
.
.
By setting sockets as non-blocking, you can effectively "ask" sockets for information. If you try to read information from a non-blocking socket and do not have any data, it does not allow blocking-it will return-1 and set errno to Ewouldblock.
But generally speaking, this kind of inquiry is not a good idea. If you allow your program to query socket data in a busy state, you will waste a lot of CPU time. A better solution is to use Select () in the next chapter to find out if there is any data to read in.
--------------------------------------------------------------------------------
Select ()--Multiple sync I/O
Although this function is a bit strange, it is useful. Suppose you are a server, and you are listening to the information on the connection while you are reading the data from the connection. No problem, you might say, isn't it just a accept () and two recv ()? Is it so easy, my friend? What if you block when calling accept ()? How can you accept recv () data at the same time? "With a non-blocking socket." No You don't want to run out of all the CPUs, do you? So, what's the good?
Select () allows you to monitor multiple sockets at the same time. If you want to know, then it will tell you which socket is ready to read, which is ready to write, and which socket has an exception (exception).
For less gossip, the following is select ():
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
int select (int Numfds, fd_set *readfds, Fd_set *writefds,fd_set
*exceptfds, struct timeval *timeout);
This function monitors a range of file descriptors, especially Readfds, Writefds, and Exceptfds. If you want to know if you can read data from standard input and socket descriptor SOCKFD, you simply add the file descriptor 0 and SOCKFD to the collection Readfds. The parameter Numfds should equal the value of the highest file descriptor plus 1. In this example, you should set the value to Sockfd+1. Because it must be larger than the standard input file descriptor (0). When the function select () is returned, the value of the Readfds is modified to reflect which file descriptor you choose to read. You can test it with the macro Fd_isset () described below. Before we go any further, let me talk about how to manipulate these collections. Each collection type is fd_set. Here are some macros to operate on this type:
Fd_zero (Fd_set *set) – Clears a collection of file descriptors
Fd_set (int fd, Fd_set *set)-Add FD to Collection
FD_CLR (int fd, fd_set *set)-Remove FD from the collection
Fd_isset (int fd, Fd_set *set) – Test whether FD is in the collection
Finally, it is a bit of a weird data structure struct timeval. Sometimes you don't want to wait for someone else to send the data around forever. Maybe when nothing happens, you want to print the string "still going ..." every 96 seconds on the terminal. This data structure allows you to set a time, and if time is up and the Select () has not yet found a prepared file descriptor, it will return for you to continue processing.
The data structure struct Timeval is this:
struct Timeval {
int tv_sec; * Seconds * *
int tv_usec; * Microseconds * *
};
Just set the tv_sec to the number of seconds you want to wait, and set the tv_usec to the number of microseconds you want to wait. Yes, it's microseconds, not milliseconds. 1,000 microseconds equals 1 milliseconds, and 1,000 milliseconds equals 1 seconds. In other words, 1 seconds equals 1,000,000 microseconds. Why use the symbol "USEC"? The letter "U" is very much like the Greek letter mu, and mu means "micro". Of course, the timeout may be the rest of the time when the function returns, because it depends on your Unix operating system.
Ha. We now have a microsecond timer. Don't calculate, the standard Unix system time slice is 100 milliseconds, so no matter how you set up your data structure struct timeval, you have to wait for so long time.
There are some interesting things to do: If you set up data structures struct timeval, you will be able to quickly time out all of the file descriptors in the collection by timing the 0,select (). If you assign the parameter timeout to NULL, the timeout will never occur until the first file descriptor is ready. Finally, if you're not very concerned about how long you're waiting, then give it to NULL.
The following code shows a wait of 2.5 seconds on the standard input:
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#define STDIN 0/* File descriptor for standard input */
Main ()
{
struct Timeval TV;
Fd_set Readfds;
Tv.tv_sec = 2;
Tv.tv_usec = 500000;
Fd_zero (&readfds);
Fd_set (STDIN, &readfds);
/* don ' t care about Writefds and Exceptfds: *
Select (stdin+1, &readfds, NULL, NULL, &AMP;TV);
if (Fd_isset (STDIN, &readfds))
printf ("A Key was pressed!/n");
Else
printf ("Timed out./n");
}
If you are on a line buffered terminal, the key you hit should be a return, or it will time out anyway.
Now, you might think that's the way to wait for data on a datagram socket--you're right: it could be. Some Unix systems can be in this way, while others cannot. You may have to look at the man page of the system before you try.
Last thing about select (): If you have a socket that is listening (listen ()), you can see if there is a new connection by adding the socket's file descriptor to the Readfds collection.
That's all I have to say about the function select ().

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.