(1) Run first - network programming

        socket (socket), socket. Two programs running in the computer establish a channel through the socket, and data is transmitted in the channel.

        The socket hides the complex TCP/IP protocol. For programmers, as long as the socket-related functions are used well, network communication can be completed.

        Socket provides two communication mechanisms: stream and datagram.

        The streaming socket is based on the TCP protocol and is an orderly, reliable, and bidirectional byte stream channel. The transmitted data will not be lost, repeated, or disordered.

        The datagram socket is based on the UDP protocol and does not need to establish and maintain a connection, which may be lost or confused. UDP is not a reliable protocol and has limitations on the length of data, but its efficiency is relatively high.

        Simple socket communication process:

Server program:

/*
 * 程序名: server.cpp 用于演示 socket 通信的服务端
 */
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>



int main(int argc, char *argv[]) {
        if (argc != 2) {
                std::cout << "Using:./server port" << std::endl;
                std::cout << "Example:./server 5005" << std::endl;;
                return -1;
        }
        // 第1步:创建服务端的 socket
        int listenfd = 0;
        if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
                perror("socket");
                return -1;
        }

        // 第2步:把服务端有用于通信的地址和端口绑定到 socket 上。
        //struct sockaddr_in serveraddr;        // 服务端地址信息的数据结构
        sockaddr_in* serveraddr = new sockaddr_in;
        serveraddr->sin_family = AF_INET;       // 协议族,在 socket 编程中只能是 AF_INET
        serveraddr->sin_addr.s_addr = htonl(INADDR_ANY);                // 任意ip地址
        //serveraddr.sin_addr.s_addr = inet_addr("192.168.199.134")     // 固定 ip 地址
        serveraddr->sin_port = htons(atoi(argv[1]));    // 指定通信端口
        if (bind(listenfd, (struct sockaddr *) serveraddr, sizeof(*serveraddr)) != 0) {
                perror("bind");
                close(listenfd);
                return -1;
        }

        // 第3步:把 socket 设置为监听模式
        if (listen(listenfd, 5) != 0) {
                perror("listen");
                close(listenfd);
                return -1;
        }

        // 第4步:接受客户端的连接
        int clientfd;   // 客户端的 socket
        int socklen = sizeof(struct sockaddr_in);       // struct sockaddr-in 大小
        struct sockaddr_in clientaddr;  // 客户端的地址信息
        clientfd = accept(listenfd, (struct sockaddr*)&clientaddr, (socklen_t*)&socklen);
        std::cout << "客户端" << inet_ntoa(clientaddr.sin_addr) << "已连接。" << std::endl;

        // 第5步:与客户端通信,接受客户端发过来的报文后,回复OK
        char buffer[1024];
        while (1) {
                int iret;
                memset(buffer, 0, sizeof(buffer));
                if ((iret = recv(clientfd, buffer, sizeof(buffer), 0)) <= 0) {
                        std::cout << "iret = " << iret << std::endl;
                        break;
                }
                std::cout << "接收: " << buffer << std::endl;

                strcpy(buffer, "OK");
                if ((iret = send(clientfd, buffer, strlen(buffer), 0)) <= 0) {
                        perror("send");
                        break;
                }
                std::cout << "发送" << buffer << std::endl;
        }

        // 第6步: 关闭 socket, 释放资源
        close(listenfd);
        close(clientfd);

}

 Client program:

/*
 * 程序名:client.cpp 为 socket 客户端  
 */
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>

int main(int argc, char* argv[]) {
        if (argc != 3) {
                std::cout << "using: ./client ip port" <<std::endl;
                std::cout << "Example:./client 127.0.0.1 5005" << std::endl;
                return -1;
        }

        // 第1步:创建客户端的socket
        int sockfd;
        if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
                perror("socket");
                return -1;
        }

        // 第2步:想服务器发起连接请求
        struct hostent* h;
        if ((h = gethostbyname(argv[1])) == 0) {        // 指定服务器的 ip 地址
                std::cout << "gethostbyname failed" << std::endl;
                close(sockfd);
                return -1;
        }
        sockaddr_in* servaddr = new sockaddr_in;
        servaddr->sin_family = AF_INET;
        servaddr->sin_port = htons(atoi(argv[2]));      // 指定服务器的通信端口
        memcpy(&servaddr->sin_addr, h->h_addr, h->h_length);
        if (connect(sockfd, (struct sockaddr*)servaddr, sizeof(*servaddr)) != 0) {      // 像服务端发起
连接
                perror("connect");
                close(sockfd);
                return -1;
        }

        char buffer[1024];
        // 第3步:与服务器通信,发送一个报文后等待回复,然后再发下一个报文
        for (int i = 0 ; i < 10; i++) {
                int iret;
                memset(buffer, 0, sizeof(buffer));
                sprintf(buffer, "这是第%d个超级女生, 编号为%03d", i + 1, i + 1);
                if ((iret = send(sockfd, buffer, strlen(buffer), 0)) <= 0) {
                        perror("send");
                        break;
                }
                std::cout << "发送:" << buffer << std::endl;


                memset(buffer, 0, sizeof(buffer));
                if ((iret = recv(sockfd, buffer, sizeof(buffer), 0)) <= 0) {
                        std::cout << "iret=" << iret << std::endl;
                        break;
                }
                std::cout << "接受: " << buffer << std::endl;
        }

        // 第4步:关闭 socket,释放资源
        close(sockfd);

}

After the program is written, use g++ to compile: g++ -o execute file name (server) program name (server.cpp)

Server running result:

Client running results:

A general understanding of the program:

(1)socket()

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

        In UNIX systems, everything is a file. The return value of the socket() function is essentially a file descriptor, which is an integer.

        A single thread will limit the number of open files at the same time, enter: ulimit -a

open files                      (-n) 1024

        Therefore, the maximum value of the socket is 1023 (starting from 0), and this value can be adjusted.

(2) sockaddr_in structure

//struct sockaddr_in serveraddr;        // 服务端地址信息的数据结构

        A defined structure used to store server address information.

        For the ip address, there are two ways of specifying the ip address and any ip address, and there are many ways of using any ip address.

(3)send()

        The send function is used to send data to the peer server through the socket, and both the server and the client use the send function to send data to the other end of the TCP connection.

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

        The function returns the number of characters sent. When an error occurs, -1 is returned, and the returned error <= 0 indicates that the communication link is no longer available.

(4)recv()

        The recv function is used to receive the data sent by the peer socket. Both the server and the client use the recv function to receive the data sent by the other end of the TCP.

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

        If the peer end of the socket does not send data, the recv function will wait; if the peer end sends data, the function returns the number of characters received. When an error occurs, -1 is returned, and the returned error <= 0 indicates that the communication link is no longer available.

(5) There are two sockets on the server side

        For the server, there are two sockets, one is used for listening, and the other is the socket created by the accept function to send and receive messages with the client after the client is successfully connected.

clientfd = accept(listenfd, (struct sockaddr*)&clientaddr, (socklen_t*)&socklen);

(6) Close the socket before the program exits

        The socket is a system resource, the number of sockets opened by the operating system is limited, and the open sockets must be closed before the program exits.

Guess you like

Origin blog.csdn.net/weixin_43284996/article/details/127976285