Socket network programming is a technology, which is often used in network communication. The biggest difference between socket and interprocess communication is that socket network programming is based on multi machine information transmission, while the former is based on single machine.
1, Understand the difference between TCP and UDP.
① TCP is connection oriented (for example, dial up to establish a connection before making a call; UDP is connectionless, that is, it is not necessary to establish a connection before sending data.
② TCP provides reliable services. In other words, the data transmitted through TCP connection is error free, not lost, not repeated, and arrives in sequence; UDP does its best to deliver, that is, reliable delivery is not guaranteed.
③ TCP is byte stream oriented. In fact, TCP regards data as a series of unstructured byte streams; UDP is a message oriented UDP without congestion control. Therefore, congestion in the network will not reduce the sending rate of the source host (very useful for real-time applications, such as IP telephony, real-time video conference, etc.).
④ Each TCP connection can only be point-to-point; UDP supports one-to-one, one to many, many to one and many to many interactive communication.
⑤ TCP header overhead 20 bytes; The overhead of UDP header is small, only 8 bytes.
⑥ The logical communication channel of TCP is a full duplex reliable channel, while UDP is an unreliable channel.
2, API for socket programming
1. Byte order conversion API
uint16_t htons(uint16_t host16bitvalue); //Returns the value of the network byte order uint32_t htonl(uint32_t host32bitvalue); //Returns the value of the network byte order uint16_t ntohs(uint16_t net16bitvalue); //Returns the value of the host byte order uint32_t ntohl(uint32_t net32bitvalue); //Returns the value of the host byte order h representative host,n representative net,s representative short(Two bytes), l representative long(4 Bytes), the conversion between host byte order and network byte order can be realized through the above four functions. Sometimes it can be used INADDR_ANY,INADDR_ANY Specify the address for the operating system to obtain
2. Address translation API
int inet_aton(const char * straddr,struct in_addr *addrp) Description: put the string form"192.168.1.123"Convert to a format recognized by the network First parameter: IP The address of the string. The second parameter: the address of the string char *inet_ntoa(struct in_addr inaddr); Network format ip Convert address to string form
3. Create communication endpoint socket
int socket(int domain, int type, int protocol); The first parameter is:Specify a communication domain,Commonly used AF_INET(IPv4 Internet protocols) The second parameter is:socket Type of formulation,Commonly used SOCK_STREAM(Provide orderly, reliable, bidirectional and connection based byte stream. It can be supported by out of band data transmission mechanism.) The third parameter is:parameter protocol Used to indicate the protocol packet to be received,Usually write 0 to receive any IP Data packet. The verification and protocol analysis are completed by the program itself Return value:If successful, the file descriptor of the new socket is returned. If failed, return-1. eg: socket(AF_INET,SOCK_STREAM,0);
4. Bind name to socket bind
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); The first parameter is:The file identifier returned when creating the communication endpoint. The second parameter is:addr Pointer to structure variable,Here we use sockaddr_in Structure, and then cast to sockaddr Type. sockaddr_in structural morphology struct sockaddr_in{ sa_family_t sin_family; //Address Family, i.e. address type uint16_t sin_port; //16 bit port number struct in_addr sin_addr; //32-bit IP address char sin_zero[8]; //Not used, usually filled with 0 }; The third parameter is:addrlen by addr The size of the variable can be determined by sizeof() Calculated. Return value:If successful, 0 is returned. When an error occurs, return-1,And set errno Appropriate. eg:bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));
5. listen to the connection on the socket
int listen(int sockfd, int backlog); The first parameter is:The file identifier returned when creating the communication endpoint. The second parameter is:backlog Parameter defines the maximum length of the pending queue sockfd Connections may increase. If the queue is full when the connection request arrives, the client may receive an indication that ECONNRE‐If the underlying protocol supports retransmission, the request can be ignored in order to succeed when trying to connect again in the future. Return value:If successful, 0 is returned. When an error occurs, return-1,And set errno Appropriate. eg:listen(s_fd,10);
6. Receive connection on socket
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); The first parameter is:The file identifier returned when creating the communication endpoint. The second parameter is: addr Is pointing sockaddr Pointer to structure, type conversion required. if it is NULL,be addrlen Also empty The third parameter is: adr Address of length. Return value:If successful, these system calls will return a nonnegative integer a The descriptor of the accepted socket. Error, return-1,errn For the appropriate settings. eg: int adr=sizeof(struct sockaddr_in); a_fd=accept(s_fd,(struct sockaddr *)&a_addr,&adr);
7. Initiate a connection on the socket connect
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen); The first parameter is the file identifier returned when creating the communication endpoint. The second parameter is: addr Is the address to access. The third parameter is: the length of the address to be accessed. Return value: 0 if successful. When an error occurs, return-1,And set errno Appropriate.
3, Server side construction (two persons)
① Create communication endpoint socket
② Bind name to socket (IP address and port number)
③ Listening connection
④ Receive socket connection
⑤ Data interaction (read, send)
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> #include <errno.h> //#include <linux/in.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> int main(int argc,char **argv) { int s_fd; int a_fd; int n_read; char readbuff[128]; char msg[128]={0}; struct sockaddr_in s_addr; struct sockaddr_in a_addr; if(argc!=3){ printf("progrm is not good\n"); exit(-1); } memset(&s_addr,0,sizeof(struct sockaddr_in)); //reset memset(&a_addr,0,sizeof(struct sockaddr_in)); //reset //1.socket s_fd=socket(AF_INET,SOCK_STREAM,0); if(s_fd == -1){ perror("socket"); exit(-1); } //2.bind s_addr.sin_family=AF_INET; s_addr.sin_port=htons(atoi(argv[2])); //s_addr.sin_addr.s_addr=("127.0.0.1"); inet_aton(argv[1],&s_addr.sin_addr); bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in)); //3.listen listen(s_fd,10); //4.accept int adr=sizeof(struct sockaddr_in); while(1){ a_fd=accept(s_fd,(struct sockaddr *)&a_addr,&adr); if(a_fd==-1){ perror("accept"); } printf("get connect:%s\n",inet_ntoa(a_addr.sin_addr)); if(fork()==0){ if(fork()==0){ while(1){ //write memset(msg,0,sizeof(msg)); printf("input: "); gets(msg); write(a_fd,msg,strlen(msg)); } } //read while(1){ memset(readbuff,0,sizeof(readbuff)); n_read=read(a_fd,readbuff,128); if(n_read==-1){ perror("read"); }else{ printf("get message from client:%d,%s\n",n_read,readbuff); } } break; } } return 0; }
4, Construction of receiving end (two persons)
① Create communication endpoint
② Initiate connection
③ Send data
④ Read data
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> #include <errno.h> //#include <linux/in.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> int main(int argc,char **argv) { int c_fd; int n_read; char readbuff[128]; char msg[128]={0}; struct sockaddr_in c_addr; if(argc!=3){ printf("progrm is not good\n"); exit(-1); } memset(&c_addr,0,sizeof(struct sockaddr_in)); //reset //1.socket c_fd=socket(AF_INET,SOCK_STREAM,0); if(c_fd == -1){ perror("socket:\n"); exit(-1); } //2.connect c_addr.sin_family=AF_INET; c_addr.sin_port=htons(atoi(argv[2])); inet_aton(argv[1],&c_addr.sin_addr); if(connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr))==-1){ perror("connect\n"); exit(-1); } while(1){ if(fork()==0){ while(1){ memset(msg,0,sizeof(msg)); printf("input: "); gets(msg); //3.write write(c_fd,msg,strlen(msg)); } } while(1){ //3.read memset(readbuff,0,sizeof(readbuff)); n_read=read(c_fd,readbuff,128); if(n_read==-1){ printf("perror:\n"); }else{ printf("I get message from server:%d,context:%s\n",n_read,readbuff); } } } return 0; }
For multi machine communication, only the server side needs to be modified
① Define mark to identify the number of client numbers
② Change accept
//4.accept int adr=sizeof(struct sockaddr_in); while(1){ a_fd=accept(s_fd,(struct sockaddr *)&a_addr,&adr); if(a_fd==-1){ perror("accept"); } mark++; printf("get connect:%s\n",inet_ntoa(a_addr.sin_addr)); if(fork()==0){ if(fork()==0){ while(1){ //write sprintf(msg,"Welcom No.%d client",mark); //Current client number write(a_fd,msg,strlen(msg)); sleep(3); } } //read while(1){ memset(readbuff,0,sizeof(readbuff)); n_read=read(a_fd,readbuff,128); if(n_read==-1){ perror("read"); }else{ printf("get message from client:%d,%s\n",n_read,readbuff); } } break; } }