当前位置:网站首页>Socket communication principle and Practice

Socket communication principle and Practice

2022-07-07 10:30:00 houxiaoni01

Course study :socket Introduction to programming
     Socket Programming details
     Socket Basic preparation for learning network
     Linux C Language implementation socket Servers and clients

This article explains in detail Socket Communication principle and practice , In this paper, the example code is introduced in detail . It has a certain reference value for everyone's study or work , Friends in need can refer to .

1、TCP/IP、UDP、Socket

Yes TCP/IP、UDP、Socket Programming these words is not new to you ? With the development of network technology , These words fill our ears . So I want to ask :

  1. What is? TCP/IP、UDP?
  2. Socket Where is it ?
  3. Socket What is it? ?
  4. Can you use them ?

1.1 What is? TCP/IP、UDP?

TCP/IP(Transmission Control Protocol/Internet Protocol) Transmission control protocol / Internet Protocol , It's an industry standard protocol set , It's for the wan (WANs) The design of the .

UDP(User Data Protocol, User datagram protocol ) Is with the TCP The corresponding agreement . It belongs to TCP/IP One of the protocol families .

Here is a picture , Showing the relationship between these agreements .

 chart 1

chart 1

TCP/IP Protocol family includes transport layer 、 The network layer 、 The link layer . Now you know TCP/IP And UDP It's over .

1.2 Socket Where is it ?

In the figure 1 in , We didn't see it Socket Shadow , So where is it ? Or talk with pictures , Be clear at a glance .

 chart 2

chart 2

original Socket ad locum .

1.3 Socket What is it? ?

Socket Is the application layer and TCP/IP Intermediate software abstraction layer for protocol family communication , It's a set of interfaces . In design mode ,Socket It's a facade pattern , It's complicated TCP/IP The protocol family is hidden in Socket The back of the interface , For users , A simple set of interfaces is all , Give Way Socket To organize data , To comply with the specified protocol .

1.4 Can you use them ?

Predecessors have done a lot for us , Communication between networks is much simpler , But after all, there is still a lot of work to do . I heard it before Socket Programming , I think it is a relatively advanced programming knowledge , But just find out Socket How programming works , The veil of mystery is lifted .

A scene in life . You have to call a friend , Dial first , A friend picks up the phone when he hears it , That's when you connect with your friends , And you can talk . When the communication is over , Hang up and end the conversation . The scene in life explains how it works , Maybe TCP/IP The agreement clan is born in life , It doesn't have to be .

 chart 3

chart 3

Start with the server . Initialize the server first Socket, And then bind to the port (bind), Listen to the port (listen), call accept Blocking , Wait for the client to connect . At this time, if there is a client initializing a Socket, And then connect to the server (connect), If the connection is successful , At this time, the connection between the client and the server is established . Client sends data request , The server receives the request and processes it , Then send the response data to the client , Client reads data , Finally, close the connection , An interaction ends .

We understand the value of information exchange , How do processes communicate with each other in the network , For example, we open the browser and browse the web every day when , How does the browser process relate to web Server communication ? When you use QQ When chatting ,QQ How does the process work with the server or where your friends are QQ Process of communication ? It all depends socket? What is socket?socket What are the types of ? also socket The basic function of , These are all what this article wants to introduce .

2、 How processes communicate with each other in the network ?

Local interprocess communication (IPC) There are many ways , But it can be summed up as follows 4 class :

  • The messaging ( The Conduit 、FIFO、 Message queue )
  • Sync ( The mutex 、 Condition variables, 、 Read-write lock 、 File and write record lock 、 Semaphore )
  • Shared memory ( Anonymous and named )
  • Remote procedure call (Solaris The door and Sun RPC)

But none of this is the subject of this article ! We are going to talk about how processes in the network communicate with each other ? The first problem to be solved is how to uniquely identify a process , Otherwise, communication is impossible ! It can be done locally through processes PID To uniquely identify a process , But it doesn't work on the Internet . Actually TCP/IP The protocol family has solved this problem for us , Network layer “ip Address ” Can uniquely identify hosts in the network , and The transport layer “ agreement + port ” Can uniquely identify applications in the host ( process ). This uses triples (ip Address , agreement , port ) You can identify the process of the network , Process communication in the network can use this flag to interact with other processes .

Use TCP/IP The application program of the protocol usually uses the application programming interface :UNIX BSD Socket (socket) and UNIX System V Of TLI( Has been eliminated ), To achieve communication between network processes . For now , Almost all applications use socket, And now it's the Internet age , Process communication is ubiquitous in the network , That's why I said “ Everything is socket”.

3、 What is? Socket?

We already know that the process in the network is through socket To communicate , What is socket Well ?socket Come of Unix, and Unix/Linux One of the basic philosophies is “ Everything is a document ”, Both can be used. “ open open –> Reading and writing write/read –> close close” Mode to operate . My understanding is that Socket It's an implementation of this pattern ,socket It's a special document , some socket Function is the operation on it ( read / Write IO、 open 、 close ), These functions are described later .

socket The origin of the word
The first use in networking is in 1970 year 2 month 12 The literature published on IETF RFC33 Found in the , The writer is Stephen Carr、Steve Crocker and Vint Cerf. According to the American Museum of computer history ,Croker writes :“ The elements of the namespace can be called socket interfaces . A socket interface forms one end of a connection , And a connection can be completely defined by a pair of socket interfaces .” The Museum of computer history added :“ This is more than BSD The socket interface definition of is about 12 year .”

4、socket Basic operation

since socket yes “open—write/read—close” An implementation of patterns , that socket The function interface corresponding to these operations is provided . Let's say TCP For example , Introduce some basic socket The interface function .

4.1、socket() function

int socket(int domain, int type, int protocol);

socket Function corresponds to the open operation of a normal file . The open operation of a normal file returns a file description word , and socket() Used to create a socket The descriptor (socket descriptor), It uniquely identifies a socket. This socket Descriptors are the same as document descriptors , Subsequent operations are useful to it , Take it as a parameter , Through it to do some reading and writing operations .

Just as you can give fopen Pass in different parameter values , To open different files . establish socket When , You can also specify different parameters to create different socket The descriptor ,socket The three parameters of the function are :

  • domain: Protocol domain , Also known as the protocol family (family). Common protocol families are ,AF_INETAF_INET6AF_LOCAL( Or called AF_UNIX,Unix Domain socket)、AF_ROUTE wait . The protocol family decided socket Address type of , The corresponding address must be used in the communication , Such as AF_INET Decided to use ipv4 Address (32 Bit ) And port number (16 Bit ) The combination of 、AF_UNIX Decided to use an absolute pathname as the address .

  • type: Appoint socket type . frequently-used socket Type a ,SOCK_STREAMSOCK_DGRAMSOCK_RAWSOCK_PACKETSOCK_SEQPACKET wait (socket What are the types of ?).

  • protocol: So it's called Siyi , It's a protocol . Common protocols are ,IPPROTO_TCPIPPTOTO_UDPIPPROTO_SCTPIPPROTO_TIPC etc. , They correspond to each other TCP Transfer protocol 、UDP Transfer protocol 、STCP Transfer protocol 、TIPC Transfer protocol ( I'll have a separate discussion on this agreement !).

Be careful : It's not the one above type and protocol Can be combined at will , Such as SOCK_STREAM You can't talk to IPPROTO_UDP Combine . When protocol by 0 when , Will automatically select type Default protocol corresponding to type .

When we call socket Create a socket when , Back to socket Descriptors exist in the protocol family (address family,AF_XXX) In the space , But there is no specific address . If you want to assign an address to it , You have to call bind() function , Otherwise, call connect()listen() The system will automatically assign a port at random .

4.2 bind() function

As mentioned above bind() Function to assign a specific address in an address family to socket. For example, it corresponds to AF_INET、AF_INET6 Is to take a ipv4 or ipv6 The combination of address and port number is assigned to socket.

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

The three parameters of the function are :

  • sockfd: namely socket Description words , It's through socket() Function creates , A unique logo socket.bind() The function will bind a name to the description word .

  • addr: One const struct sockaddr * The pointer , Point to bind to sockfd Agreement address for . This address structure is created according to the address socket When the address protocol family is different , Such as :

//ipv4 The corresponding is :

struct sockaddr_in {
    
    sa_family_t    sin_family; 
    in_port_t      sin_port;   
    struct in_addr sin_addr;   
};

struct in_addr {
    
    uint32_t       s_addr;     
};

//ipv6 The corresponding is :

struct sockaddr_in6 {
     
    sa_family_t     sin6_family;    
    in_port_t       sin6_port;      
    uint32_t        sin6_flowinfo;  
    struct in6_addr sin6_addr;      
    uint32_t        sin6_scope_id;  
};

struct in6_addr {
     
    unsigned char   s6_addr[16];    
};

//Unix The domain corresponds to :

#define UNIX_PATH_MAX 108

struct sockaddr_un {
     
    sa_family_t sun_family;                
    char        sun_path[UNIX_PATH_MAX];   
};
  • addrlen: It corresponds to the length of the address .

Usually the server will bind a well-known address when it starts ( Such as ip Address + Port number ), Used to provide services , The client can connect to the server through it ; And the client doesn't have to specify , The system automatically assigns a port number and its own ip Address combination . That's why the server is usually on listen We'll call bind(), And the client will not call , But in connect() The system randomly generates a .

Network byte order and host byte order
Host byte order : It's what we usually call the big end and small end mode : Different CPU There are different byte order types , These byte orders refer to the order in which integers are stored in memory , This is called host sequence . Quoting standard Big-Endian and Little-Endian Is defined as follows :
  a) Little-Endian That is, the low byte is discharged at the low address end of the memory , The high byte is placed at the high address end of the memory .
  b) Big-Endian That is, the high byte is discharged at the low address side of the memory , The low byte is placed at the high address of the memory .
Network byte order :4 Bytes of 32 bit Values are transmitted in the following order :( High byte ------------------->------------------- Low byte ) First of all 0~7bit, secondly 8~15bit, then 16~23bit, And finally 24~31bit. This order of transmission is called big endian . because TCP/IP All binary integers in the header are required to be in this order when they are transmitted in the network , So it's also called network byte order . Byte order , As the name implies, the order of bytes , It is the storage order of data larger than one byte in memory , A byte of data is out of order .
therefore : Binding an address to socket When , Please convert the host byte order to network byte order first , Do not assume that the host byte order is the same as the network byte order Big-Endian. because This problem has led to bloody cases ! Because of this problem in the company project code , It leads to a lot of inexplicable problems , So remember not to make any assumptions about the host byte order , Be sure to convert it into network byte order Assign to socket.

It should be noted that struct in_addr Medium s_addr It's a kind of uint32_t Data of type , And in network transmission , Unification is to transmit data in network byte order of large end order , And we are usually used to IP The address format is dotted decimal , for example :“219.228.148.169”, At this time, the following functions will be called for conversion , take IP Address converted to 32 Bit integer data , At the same time, network byte conversion :

in_addr_t inet_addr (const char *__cp) __THROW;
// perhaps 
int inet_aton (const char *__cp, struct in_addr *__inp) __THROW;	//windows No such function  

If we only need to convert network byte order address , You can use the following functions :

/*Functions to convert between host and network byte order. Please note that these functions normally take `unsigned long int' or `unsigned short int' values as arguments and also return them. But this was a short-sighted decision since on different systems the types may have different representations but the values are always the same. */ 

// h Represents the host byte order 
// n Represents network byte order 
// s representative short(4 byte )
// l representative long(8 byte )
extern uint32_t ntohl (uint32_t __netlong) __THROW __attribute__ ((__const__));
extern uint16_t ntohs (uint16_t __netshort) __THROW __attribute__ ((__const__));
extern uint32_t htonl (uint32_t __hostlong) __THROW __attribute__ ((__const__));
extern uint16_t htons (uint16_t __hostshort)__THROW __attribute__ ((__const__));

4.3 listen()、connect() function

If as a server , Calling socket()bind() After that, it will call listen() To monitor this socket, If the client calls connect() Make a connection request , The server will receive the request .

int listen(int sockfd, int backlog);

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

listen The first parameter of the function is the one to listen to socket Description words , The second parameter is the corresponding socket The maximum number of connections that can be queued .socket() Function created socket The default is an active type ,listen Function will socket Become passive , Waiting for customer's connection request .

connect The first parameter of the function is the client's socket Description words , The second parameter is... Of the server socket Address , The third parameter is zero socket The length of the address . The client calls connect Function to establish and TCP Server connection .

4.4 accept() function

TCP The server calls... In turn socket()bind()listen() after , Will monitor the designated socket Address .TCP The client calls... In turn socket()connect() After that, I went to TCP The server sent a connection request .TCP After the server listens for the request , Will call accept() Function to receive the request , So the connection is established . Then we can start the Internet I/O Operation , That is, reading and writing similar to ordinary documents I/O operation .

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

accept The first parameter of the function is... Of the server socket Description words , The second parameter is pointing to struct sockaddr * The pointer to , Used to return the protocol address of the client , The third parameter is the length of the protocol address . If accpet success , So its return value is a new description word automatically generated by the kernel , Representing and returning customers TCP Connect .

Be careful : accept The first parameter of is the... Of the server socket Description words , It's the server that starts calling socket() Function generated , be called monitor socket Description words ; and accept Function returns Connected socket Description words . A server usually only creates one listener socket Description words , It exists throughout the life of the server . The kernel creates a connection for each client connection accepted by the server process socket Description words , When the server completes the service to a certain customer , Corresponding connected socket The descriptors are closed .【 monitor socket It's like welcoming guests in a hotel , When the guest is received and handed over to other waiters in the hotel , His work is finished . and accept The new socket generated is the waiter in the hotel , The whole process of subsequent communication is the socket , A waiter like this will always serve guests 】

4.5 read()、write() Such as function

Everything is in place only a strong wind , Now the server has established a connection with the customer . You can call the network I/O Read and write it , That is, the communication between different processes in the network is realized ! The Internet I/O There are several groups of operations :

  • read()/write()
  • recv()/send()
  • readv()/writev()
  • recvmsg()/sendmsg()
  • recvfrom()/sendto()

I recommend using recvmsg()/sendmsg() function , These two functions are the most common I/O function , You can actually replace all the other functions above with these two functions . Their statements are as follows :

#include <unistd.h>

ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);

#include <sys/types.h>
#include <sys/socket.h>

ssize_t send(int sockfd, const void *buf, size_t len, int flags);
ssize_t recv(int sockfd, void *buf, size_t len, int flags);

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
               const struct sockaddr *dest_addr, socklen_t addrlen);
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                 struct sockaddr *src_addr, socklen_t *addrlen);

ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);

read The function is responsible for from fd Read content in . When the reading is successful ,read Returns the actual number of bytes read , If the value returned is 0 Indicates that the end of the file has been read , Less than 0 Indicates that there is a mistake . If the error is EINTR Explain that reading is caused by interruption , If it is ECONNREST Indicates that there is a problem with the network connection .

write Function will buf Medium nbytes Byte contents written to file descriptor fd. Returns the number of bytes written on success , Return... On failure -1, And set up errno Variable . In a web program , When we write to the socket file descriptor, there are two possibilities .

  • 1)write The return value of is greater than 0, Indicates that some or all of the data has been written .
  • 2) The value returned is less than 0, There was a mistake . We have to deal with it according to the type of error .

If the error is EINTR Indicates an interrupt error occurred while writing . If EPIPE Indicates that there is a problem with the network connection ( The other party has closed the connection ).

I'm not going to introduce these other pairs one by one I/O Function , Specific see man Document or baidu、Google, The following example will be used to send/recv.

4.6 close() function

After the server has established a connection with the client , I can do some reading and writing , After reading and writing, close the corresponding socket Description words , It's like opening a file after operation fclose Close open files .

#include <unistd.h>

int close(int fd);

close One TCP socket The default behavior is to socket Mark as closed , Then immediately return to the calling process . The descriptor can no longer be used by the calling process , That is to say, we can no longer do read or write The first parameter of .

Be careful :close The operation just makes the corresponding socket Reference count of descriptive words -1, Only if the reference count is 0 When , Will trigger TCP The client sends a termination request to the server .

5、socket in TCP Three handshakes to establish a connection

We know tcp To establish a connection “ Three handshakes ”, That is, three packets are exchanged . The general flow is as follows :

  • The client sends a... To the server SYN J
  • The server responds to the client with a SYN K, Also on SYN J Confirm ACK J+1
  • The client sends a confirmation to the server ACK K+1

Only three handshakes , But this three handshake happened in socket Among the functions of ? Please look at the chart below. :

 Insert picture description here

chart 4、socket Sent in TCP Three handshakes

As you can see from the diagram , When the client calls connect when , Connection request triggered , Sent... To the server SYN J package , At this time connect Go into blocking mode ; The server listens for connection requests , I will receive SYN J package , call accept Function to receive the request and send it to the client SYN K ,ACK J+1, At this time accept Go into blocking mode ; Client receives server's SYN K ,ACK J+1 after , At this time connect return , Also on SYN K Confirm ; Server received ACK K+1 when ,accept return , Now the three handshakes are over , Connection is established .

summary : Client's connect On the second return of the three handshakes , On the server side accept On the third return of the three handshakes .

6、socket in TCP Four handshake release connection details

It says socket in TCP The establishment process of three handshakes , And what it involves socket function . Now let's introduce socket The process of releasing a connection with four handshakes in , Please look at the chart below. :

image

chart 5、socket Sent in TCP Four handshakes

The process is as follows :

  • An application process first calls close Active close connection , At this time TCP Send a FIN M;
  • The other end receives FIN M after , Perform passive shutdown , For this FIN Confirm . Its reception is also passed to the application process as a file Terminator , because FIN It means that the application process can no longer receive additional data on the corresponding connection ;
  • After a while , Receive the application process call of the end of file close Turn it off socket. This leads to its TCP Also send a FIN N;
  • Received this FIN Source sender of TCP Confirm it .

So there's one in every direction FIN and ACK.

7、 Process and implementation

7.1 TCP

be based on TCP( Connection oriented ) Of socket Programming , It is divided into client side and server side .

The process of the client is as follows :

(1) Create socket (socket)
(2) Send a connection request to the server (connect)
(3) Communicate with the server (send/recv)
(4) Close socket

The process of the server side is as follows :

(1) Create socket (socket)
(2) Bind the socket to a local address and port (bind)
(3) Set the socket to listen mode , Ready to receive client requests (listen)
(4) Waiting for customer requests ; When the request comes , Accept connection request , Returns a new socket corresponding to this connection (accept)
(5) Use the socket returned to communicate with the client (send/recv)
(6) return , Waiting for another customer request .
(7) Close socket .

Server side :

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>

#define MAXLINE 4096

int main(int argc, char** argv)
{
    
    int    listenfd, connfd;
    struct sockaddr_in     servaddr;
    char    buff[4096];
    int     n;

    if( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ){
    
        printf("create socket error: %s(errno: %d)/n",strerror(errno),errno);
        exit(0);
    }

    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(6666);

    if( bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1){
    
        printf("bind socket error: %s(errno: %d)/n",strerror(errno),errno);
        exit(0);
    }

    if( listen(listenfd, 10) == -1){
    
        printf("listen socket error: %s(errno: %d)/n",strerror(errno),errno);
        exit(0);
    }

    printf("======waiting for client's request======/n");
    while(1){
    
        if( (connfd = accept(listenfd, (struct sockaddr*)NULL, NULL)) == -1){
    
            printf("accept socket error: %s(errno: %d)",strerror(errno),errno);
            continue;
        }
        n = recv(connfd, buff, MAXLINE, 0);
        buff[n] = '/0';
        printf("recv msg from client: %s/n", buff);
        close(connfd);
    }

    close(listenfd);
}

client :

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>

#define MAXLINE 4096

int main(int argc, char** argv)
{
    
    int    sockfd, n;
    char    recvline[4096], sendline[4096];
    struct sockaddr_in    servaddr;

    if( argc != 2){
    
        printf("usage: ./client <ipaddress>/n");
        exit(0);
    }

    if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
    
        printf("create socket error: %s(errno: %d)/n", strerror(errno),errno);
        exit(0);
    }

    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(6666);
    if( inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0){
    
        printf("inet_pton error for %s/n",argv[1]);
        exit(0);
    }

    if( connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0){
    
        printf("connect error: %s(errno: %d)/n",strerror(errno),errno);
        exit(0);
    }

    printf("send msg to server: /n");
    fgets(sendline, 4096, stdin);
    if( send(sockfd, sendline, strlen(sendline), 0) < 0)
    {
    
        printf("send msg error: %s(errno: %d)/n", strerror(errno), errno);
        exit(0);
    }

    close(sockfd);
    exit(0);
}

7.2 UDP

UDP The protocol is a connectionless , Unreliable data report (SOCK_DGRAM) Transport services . Use UDP Sockets do not need to establish connections , The server is calling socket() Generate a socket and call bind() After binding the port, you can communicate (recvfrom Functions and sendto function ) 了 ; The client is in use socket() After generating a socket, you can send and receive data to the server address .

Special attention needs to be paid here :TCP Using a stream socket (SOCK_STREAM),UDP Datagram socket is used (SOCK_DGRAM).

Server side :

#include<sys/types.h> 
#include<sys/socket.h> 
#include<unistd.h> 
#include<netinet/in.h> 
#include<arpa/inet.h> 
#include<stdio.h> 
#include<stdlib.h> 
#include<errno.h> 
#include<netdb.h> 
#include<stdarg.h> 
#include<string.h> 
  
#define SERVER_PORT 8000 
#define BUFFER_SIZE 1024 
#define FILE_NAME_MAX_SIZE 512 
  
int main() 
{
     
    /*  establish UDP Socket connector  */
    struct sockaddr_in server_addr; 
    bzero(&server_addr, sizeof(server_addr)); 
    server_addr.sin_family = AF_INET; 
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY); 
    server_addr.sin_port = htons(SERVER_PORT); 

    /*  establish socket */
    int server_socket_fd = socket(AF_INET, SOCK_DGRAM, 0); 
    if(server_socket_fd == -1) 
    {
     
        perror("Create Socket Failed:"); 
        exit(1); 
    } 
  
    /*  Binding socket interface  */
    if(-1 == (bind(server_socket_fd,(struct sockaddr*)&server_addr,sizeof(server_addr)))) 
    {
     
        perror("Server Bind Failed:"); 
        exit(1); 
    } 

    /*  The data transfer  */
    while(1) 
    {
      
        /*  Define an address , Used to capture the client address  */
        struct sockaddr_in client_addr; 
        socklen_t client_addr_length = sizeof(client_addr); 

        /*  receive data  */
        char buffer[BUFFER_SIZE]; 
        bzero(buffer, BUFFER_SIZE); 
        if(recvfrom(server_socket_fd, buffer, BUFFER_SIZE,0,(struct sockaddr*)&client_addr, &client_addr_length) == -1) 
        {
     
            perror("Receive Data Failed:"); 
            exit(1); 
        } 

        /*  from buffer Copy out file_name */
        char file_name[FILE_NAME_MAX_SIZE+1]; 
        bzero(file_name,FILE_NAME_MAX_SIZE+1); 
        strncpy(file_name, buffer, strlen(buffer)>FILE_NAME_MAX_SIZE?FILE_NAME_MAX_SIZE:strlen(buffer)); 
        printf("%s", file_name); 
    } 
    close(server_socket_fd); 
    return 0; 
}

client :

#include<sys/types.h> 
#include<sys/socket.h> 
#include<unistd.h> 
#include<netinet/in.h> 
#include<arpa/inet.h> 
#include<stdio.h> 
#include<stdlib.h> 
#include<errno.h> 
#include<netdb.h> 
#include<stdarg.h> 
#include<string.h> 
  
#define SERVER_PORT 8000 
#define BUFFER_SIZE 1024 
#define FILE_NAME_MAX_SIZE 512 
  
int main() 
{
    
    /*  Server address  */
    struct sockaddr_in server_addr; 
    bzero(&server_addr, sizeof(server_addr)); 
    server_addr.sin_family = AF_INET; 
    server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); 
    server_addr.sin_port = htons(SERVER_PORT); 

    /*  establish socket */
    int client_socket_fd = socket(AF_INET, SOCK_DGRAM, 0); 
    if(client_socket_fd < 0) 
    {
     
        perror("Create Socket Failed:"); 
        exit(1); 
    } 
  
    /*  Enter the file name into the buffer  */
    char file_name[FILE_NAME_MAX_SIZE+1]; 
    bzero(file_name, FILE_NAME_MAX_SIZE+1); 
    printf("Please Input File Name On Server: "); 
    scanf("%s", file_name); 

    char buffer[BUFFER_SIZE]; 
    bzero(buffer, BUFFER_SIZE); 
    strncpy(buffer, file_name, strlen(file_name)>BUFFER_SIZE?BUFFER_SIZE:strlen(file_name)); 
  
    /*  Send filename  */
    if(sendto(client_socket_fd, buffer, BUFFER_SIZE,0,(struct sockaddr*)&server_addr,sizeof(server_addr)) < 0) 
    {
     
        perror("Send File Name Failed:"); 
        exit(1); 
    } 

    close(client_socket_fd); 
    return 0; 
}

7.3 An example of the implementation is given below

First , Let's first give a screenshot of the implementation

 Insert picture description here

The server-side code is as follows :

#include "InitSock.h" 
#include <stdio.h> 
#include <iostream>
using namespace std;
CInitSock initSock;     //  initialization Winsock library  
 
int main() 
{
     
    //  Create a slug  
    SOCKET sListen = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	// Used to specify the address format used by the socket , Usually use AF_INET
    // Specify the type of socket , if SOCK_DGRAM, It uses udp Unreliable transmission 
	// coordination type Parameters use , Specify the type of protocol to use ( When the socket type is specified , It can be set to 0, Because the default is UDP or TCP)
    if(sListen == INVALID_SOCKET) 
    {
     
        printf("Failed socket() \n"); 
        return 0; 
    } 
     
    //  fill sockaddr_in structure  , It's a structure 
	/* struct sockaddr_in { short sin_family; // Address family ( Specify the address format ) , Set to AF_INET u_short sin_port; // Port number  struct in_addr sin_addr; //IP Address  char sin_zero[8]; // Kongzi Festival , Set to null  } */
 
    sockaddr_in sin; 
    sin.sin_family = AF_INET; 
    sin.sin_port = htons(4567);  //1024 ~ 49151: Port number registered by ordinary users 
    sin.sin_addr.S_un.S_addr = INADDR_ANY; 
     
    //  Bind this socket to a local address  
    if(::bind(sListen, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR) 
    {
     
        printf("Failed bind() \n"); 
        return 0; 
    } 
     
    //  Enter monitor mode  
	//2 refer to , The maximum number of unprocessed connections allowed to remain in the listening queue 
 
    if(::listen(sListen, 2) == SOCKET_ERROR) 
    {
     
        printf("Failed listen() \n"); 
        return 0; 
    } 
     
    //  Loop to accept client's connection request  
    sockaddr_in remoteAddr;  
    int nAddrLen = sizeof(remoteAddr); 
    SOCKET sClient = 0; 
    char szText[] = " TCP Server Demo! \r\n"; 
    while(sClient==0) 
    {
     
        //  Accept a new connection  
		//((SOCKADDR*)&remoteAddr) A pointer to a sockaddr_in Pointer to structure , Used to get the other party's address 
        sClient = ::accept(sListen, (SOCKADDR*)&remoteAddr, &nAddrLen); 
        if(sClient == INVALID_SOCKET) 
        {
     
            printf("Failed accept()"); 
        } 
         
         
        printf(" Receiving a connection :%s \r\n", inet_ntoa(remoteAddr.sin_addr)); 
        continue ; 
    } 
 
    while(TRUE) 
    {
     
        //  Send data to client  
        gets(szText) ; 
        ::send(sClient, szText, strlen(szText), 0); 
         
        //  Receive data from client  
        char buff[256] ; 
        int nRecv = ::recv(sClient, buff, 256, 0); 
        if(nRecv > 0) 
        {
     
            buff[nRecv] = '\0'; 
            printf("  Data received :%s\n", buff); 
        } 
     
    } 
 
    //  Close the connection to the client  
    ::closesocket(sClient); 
         
    //  Turn off the monitor socket  
    ::closesocket(sListen); 
 
    return 0; 
} 

Client code :

#include "InitSock.h" 
#include <stdio.h> 
#include <iostream> 
using namespace std;
CInitSock initSock;     //  initialization Winsock library  
 
int main() 
{
     
    //  Create a slug  
    SOCKET s = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
    if(s == INVALID_SOCKET) 
    {
     
        printf(" Failed socket() \n"); 
        return 0; 
    } 
     
    //  You can also call... Here bind Function to bind a local address  
    //  Otherwise, the system will automatically arrange  
     
    //  Fill in the remote address information  
    sockaddr_in servAddr;  
    servAddr.sin_family = AF_INET; 
    servAddr.sin_port = htons(4567); 
    //  Be careful , Here is the server program (TCPServer Program ) Of the machine IP Address  
    //  If your computer is not connected to the Internet , Use it directly 127.0.0.1 that will do  
    servAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); 
     
    if(::connect(s, (sockaddr*)&servAddr, sizeof(servAddr)) == -1) 
    {
     
        printf(" Failed connect() \n"); 
        return 0; 
    } 
     
    char buff[256]; 
    char szText[256] ; 
     
    while(TRUE) 
    {
     
        // Receive data from the server  
        int nRecv = ::recv(s, buff, 256, 0); 
        if(nRecv > 0) 
        {
     
            buff[nRecv] = '\0'; 
            printf(" Data received :%s\n", buff); 
        } 
 
        //  Send data to the server  
 
        gets(szText) ; 
        szText[255] = '\0'; 
        ::send(s, szText, strlen(szText), 0) ; 
         
    } 
     
    //  Turn off the slug  
    ::closesocket(s); 
    return 0; 
} 

Packaged InitSock.h

#include <winsock2.h> 
#include <stdlib.h> 
#include <conio.h> 
#include <stdio.h> 
 
#pragma comment(lib, "WS2_32") //  link to WS2_32.lib 
 
class CInitSock      
{
     
public: 
    CInitSock(BYTE minorVer = 2, BYTE majorVer = 2) 
    {
     
        //  initialization WS2_32.dll 
        WSADATA wsaData; 
        WORD sockVersion = MAKEWORD(minorVer, majorVer); 
        if(::WSAStartup(sockVersion, &wsaData) != 0) 
        {
     
            exit(0); 
        } 
    } 
    ~CInitSock() 
    {
        
        ::WSACleanup();  
    } 
}; 

This is about Socket This is the article on communication principles and practices . I hope it will be helpful for your study , I also hope you can support script house more .

原网站

版权声明
本文为[houxiaoni01]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/188/202207070814084550.html