Linux introductory training tutorial linux network programming socket introduction

1. Concept introduction

  Network programs are divided into server programs and client programs. The server is the party that provides the service, and the client is the party that requests the service. But the actual situation is that the roles of the client and the server of some programs are not so obvious, that is, they are the Linux training

client .

  When we write network programs, network communication is generally based on the TCP protocol or the UDP protocol. Brothers Linux training editor:

  TCP: (Transfer Control Protocol) Transmission Control Protocol is a connection-oriented protocol. When our network program uses this protocol, the network can ensure the transmission between our client and server. is reliable.

  UDP: (User Datagram Protocol) User Datagram Protocol is a non-connection-oriented protocol, this protocol does not guarantee that the connection of our network program is reliable.

  Which type of protocol the network program we write adopts depends on the specific situation. For example, if it is a large amount of data communication, and the data integrity requirements are not particularly high, the UDP protocol can be used to obtain a faster transmission rate. If we want to implement some functions such as file transfer and social communication, we need to use TCP protocol communication to ensure the reliability of transmission.

  2. Introduction to elementary network functions

  nt socket (int domain, inttype, int protocol)

  domain: Explain the communication protocol family (AF_UNIX and AF_INET, etc.) used by the host where our network program is located.

  AF_UNIX can only be used for inter-process communication in a single Unix system ,

  and AF_INET is for the Internet, so it can allow remote

  Communication between hosts (when we man socket, we found that the domain option is PF_* instead of AF_*, because glibc is an implementation of posix, so PF is used instead of AF,

  but we can all use it).

  Type: used by our network program The communication protocol (SOCK_STREAM, SOCK_DGRAM, etc.)

  SOCK_STREAM indicates that we are using the TCP protocol, which will provide a sequential, reliable, bidirectional, connection-oriented bit stream.

  SOCK_DGRAM indicates that we are using the UDP protocol, which will only provide fixed-length , unreliable, connectionless communication.

  Protocol: Since we specified the type, we generally only need to use 0 instead of the socket to make basic preparations for network communication.

  Return the file descriptor when successful, and return when it fails -1, look at errno to know the details of the error.

  int bind(int sockfd, structsockaddr *my_addr, int addrlen)

  sockfd: is the file descriptor returned by the socket call.

  addrlen: is the length of the sockaddr structure.

  my_addr: is a pointer to A pointer to sockaddr. There is a definition of sockaddr in

  struct sockaddr{

  unisgned short as_family;

  char sa_data[14];

  };

  However, due to the compatibility of the system, we generally do not use this header file, but use another structure (struct sockaddr_in) instead. There is a definition of sockaddr_in in

  struct sockaddr_in{

  unsigned short sin_family;

  unsigned short intsin_port;

  struct in_addr sin_addr;

  unsigned char sin_zero [8];

  }

  We mainly use the Internet, so

  sin_family is generally AF_INET,

  sin_addr is set to INADDR_ANY to indicate that it can communicate with any host,

  sin_port is the port number we want to monitor. sin_zero[8] is used for filling.

  bind will local The port is bundled with the file descriptor returned by the socket. The success is to return 0, the failure is the same as the socket

  int listen(int sockfd, intbacklog)

  sockfd: is the file descriptor after bind.

  backlog: Set the maximum length of the request queue. When there are multiple client programs connected to the server, use this to indicate the queue length that can be introduced. The

  listen function turns the bind file descriptor into a listening socket. The return is the same as bind.

  int accept(int sockfd, struct sockaddr *addr, int *addrlen)

  sockfd: is the file descriptor after listen.

  addr and addrlen are used to fill in the program on the client side, and the server side only needs to pass the pointer. bind, listen and accept are the functions used by the server side.

  When accept is called, the server side The program will block until a client program sends a connection. When accept is successful, it returns the last server-side file descriptor, at

  which time the server-side can write information to the descriptor. If it fails, return -1

  int connect(int sockfd, struct sockaddr * serv_addr,int addrlen)

  sockfd: the file descriptor returned by socket.

  serv_addr: stores the connection information of the server. Sin_add is the address of the server

  addrlen: the length of serv_addr The

  connect function is used by the client to connect with the server. Success Returns 0 when sockfd is a file descriptor that fails to communicate with the server and returns -1.

  For more functions, please refer to man …….

  int getaddrinfo(const char*node, const char *service,

  const struct addrinfo*hints,

  struct addrinfo **res);

  3. Elementary network function usage example

  A textbook-style server-side program flow is:

  Establish socket socket() ---> bind the socket to the ip address bind() -----> establish a listening socket listen() ------> start waiting for the client to request accpet ()

  The detailed code is as follows:

  Copy the code as follows:

  #include <stdlib.h>

  #include <stdio.h>

  #include <errno.h>

  #include <string.h>

  #include <unistd.h>

  #include<sys /socket.h>

  #include<netinet/in.h>

  #include<sys/types.h>

  #include <netdb.h>

  int main(int argc, char*argv[])

  {

  int sockfd,connfd;

  struct sockaddr_in srvaddr;

  struct sockaddr_in cliaddr;

  int len,port;

  charhello[]="Hi,welcome to linux-code!\n";

  if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1){

  fprintf(stderr,"Socketerror:%s\n\a",strerror(errno));

  exit(1);

  }

  /* 服务器端填充 sockaddr结构 */

  bzero(&srvaddr,sizeof(structsockaddr_in));

  srvaddr.sin_family=AF_INET;

  srvaddr.sin_addr.s_addr=htonl(INADDR_ANY);

  srvaddr.sin_port=htons(1113);

  /* 捆绑sockfd描述符 */

  if(bind(sockfd,(structsockaddr *)(&srvaddr),sizeof(struct sockaddr))==-1){

  fprintf(stderr,"Binderror:%s\n\a",strerror(errno));

  exit(1);

  }

  /* 监听sockfd描述符 */

  if(listen(sockfd,5)==-1){

  fprintf(stderr,"Listenerror:%s\n\a",strerror(errno));

  exit(1);

  }

  len=sizeof(structsockaddr_in);

  while(1){ /* The server blocks until the client program establishes a connection */

  if((connfd=accept(sockfd,(structsockaddr *)(&cliaddr),&len))==-1){

  fprintf(stderr,"Accepterror: %s\n\a",strerror(errno));

  exit(1);

  }

  fprintf(stderr,"Serverget connection from %s\n",inet_ntoa(cliaddr.sin_addr));

  if(write(connfd,hello, strlen(hello))==-1){

  fprintf(stderr,"WriteError:%s\n",strerror(errno));

  exit(1);

  }

  /* This communication has ended */

  close(connfd);

  / * Loop the next one*/

  }

  close(sockfd);

  exit(0);

  }

  A textbook-style client program flow is:

  establish a socket socket() ---> establish a connection with the server connect() The

  detailed code is as follows:

  Copy the code The code is as follows:

  #include < stdlib.h>

  #include <stdio.h>

  #include <errno.h>

  #include <string.h>

  #include <unistd.h>

  #include<sys/socket.h>

  #include<netinet/in.h>

  #include <sys/types.h>

  #include <netdb.h>

  int main(int argc, char*argv[]) {

  int sockfd; char buf[1024];

  struct sockaddr_in srvaddr;

  struct hostent *phost; intnbytes;

  if(argc!=3){

  fprintf(stderr,"Usage:%s<IP> <portnumber>\a\n",argv[0]);

  exit(1);

  }

  /* 客户程序开始建立 sockfd描述符 */

  if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1){

  fprintf(stderr,"socketError:%s\a\n",strerror(errno));

  exit(1);

  }

  /* The client program fills the data of the server */

  bzero(&srvaddr,sizeof(srvaddr));

  srvaddr.sin_family=AF_INET;

  srvaddr.sin_port=htons(atoi(argv[2]));

  if (inet_pton(AF_INET,argv[1 ] ], &srvaddr.sin_addr) <= 0){

  fprintf(stderr,"inet_ptonError:%s\a\n",strerror(errno));

  exit(1);

  }

  /* Client initiates a connection request*/

  if(connect (sockfd,(structsockaddr *)(&srvaddr),sizeof(struct sockaddr))==-1){

  fprintf(stderr,"connectError:%s\a\n",strerror(errno));

  exit(1);

  }

  /* Connection succeeded*/

  if((nbytes=read(sockfd,buf,1024))==-1){

  fprintf(stderr,"readError:%s\n",strerror(errno));

  exit(1) ;

  }

  buf[nbytes]='\0';

  printf("received data:%s\n",buf);

  /* End the communication*/

  close(sockfd);

  exit(0);

  }

  4. Problems with the above program

  First run the server program of the above program, and then run Client program, you can get the following results:

  Server side results:

  viidiot@ubuntu:~/code $./srv

  Server get connection from192.168.1.153

  Server get connection from127.0.0.1

  Server get connection

  from192.168.1.153Client End result:

  viidiot@ubuntu:~/code $./cli 192.168.1.153 1113

  received data:Hi,welcome tolinux-code!

  We have completed a simple network communication program, the io model used by the program is synchronous blocking (blocking). The server side calls accept(), write() and other functions. If no client is connected or the corresponding file descriptor is not ready to be written, the program will wait there and do nothing. In practical applications, such programs rarely appear. In practice, the asynchronous io model is used.



Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326442172&siteId=291194637