소켓 원격 호스트 네트워크 통신, 자세한 설명 + 예제! ! !

  목차

1. 기본 개념

2. 원리

2.1 소켓

2.2 바인딩

2.3 들어

2.4 수락

2.5 연결

2.6 읽기 / 수신

2.7 쓰기 / 보내기

2.8 닫기 

세, 예

네, 요약

다섯, 참고 문헌


네트워크 프로그래밍은 작업이나 인터뷰에서 접하게 될 Linux에서 매우 중요한 지식입니다.이 기사에서는 소켓 네트워크 통신을 예제와 함께 설명합니다. 시작합시다!

1. 기본 개념

소켓은 일반적으로 네트워크의 다른 호스트에있는 응용 프로그램 프로세스 간의 양방향 통신을위한 끝점의 추상화 인 소켓이라고합니다. 소켓은 상위 계층 애플리케이션을위한 통신 인터페이스를 제공합니다. 아래 그림을 참조하십시오.

그림 1 네트워크 계층                       

위 그림에서 볼 수 있듯이 소켓은 본질적으로 추상화 계층이며 다음과 같은 다양한 프로토콜을 캡슐화하고 상위 계층 응용 프로그램의 호출을 용이하게합니다. 

2. 원리

섬기는 사람:

1. 소켓 함수를 통해 소켓 설명자를 만듭니다.

2. 주소를 만들고 bind를 사용하여 주소를 소켓 설명자 (이 소켓을 청취 소켓이라고 함)에 바인딩합니다.

3. 그런 다음 listen을 사용하여 소켓 설명자를 청취 모드로 설정하고 연결 대기 큐의 길이를 설정하십시오.

4. 연결이 있으면 accept를 사용하여 연결을 꺼내고 지정된 클라이언트와 연결을 설정하고 클라이언트와의 통신을위한 새 소켓을 만듭니다.이 소켓을 연결된 소켓이라고합니다.

5. 읽기 / 쓰기 기능을 사용하여 서로 통신합니다.

6. 모든 통신이 완료된 후 닫기 기능을 사용하여 소켓을 닫으십시오.

고객:

1. 소켓을 통해 소켓을 만듭니다.

2. 연결을 통해 지정된 서버와 연결합니다.

3. 연결이 성공하면 읽기 / 쓰기를 통해 통신합니다.

4. 통신 종료 후 닫기 기능을 통해 소켓을 닫습니다.

서로 다른 응용 프로그램 간의 통신 프로세스는 다음과 같습니다.

그림 2 소켓 네트워크 통신

먼저 위 그림에서 사용 된 기능을 소개합니다.

2.1 소켓

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

이 함수는 int 유형 소켓을 반환하며, 이는 고유하며 open 함수에 의해 생성 된 파일 설명자와 비교할 수 있습니다.

2.2 바인딩

int bind(int socket, const struct sockaddr *address, socklen_t address_len);

이 함수는 소켓에 의해 생성 된 소켓에 주소를 바인딩합니다.

2.3 들어

int listen(int sockfd, int backlog);

이 기능은 서버가 클라이언트 (다른 ​​프로세스)로부터 요청을받을 수 있도록 서버에서 사용됩니다.

2.4 수락

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

 이 함수는 완료된 연결의 대기열에서 연결을 가져와 동시에 연결된 소켓이라고하는 새 (연결된) 소켓을 반환합니다. 소켓이 생성 한 소켓은 청취 소켓입니다. 소켓은 하나뿐입니다. 연결된 소켓의 각 TCP 연결은 하나를 생성합니다.

2.5 연결

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

클라이언트는 연결 기능을 통해 서버와 연결하며 TCP 프로토콜을 사용하는 경우 3 방향 핸드 셰이크 프로세스입니다.

2.6 읽기 / 수신

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

 이 함수는 fd / sockfd에서 콘텐츠를 읽는 역할을합니다.

2.7 쓰기 / 보내기

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

쓰기 / 보내기 buf의 데이터를 파일 기술자 fd / sockfd에 씁니다.

2.8 닫기 

int close(int sockfd);

소켓을 닫습니다.

위 함수는 성공하면 0, 실패하면 -1을 반환하며 오류 정보는 errno에 저장됩니다.

세, 예

서버 코드 :

#include <sys/time.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define PORT 3322   // 服务器端口

#define BACKLOG 1
#define MAXRECVLEN 1024

int main(int argc, char *argv[])
{
    char buf[MAXRECVLEN];
    int listenfd, connectfd;   // listendfd 监听套接字  connectfd 已连接套接字
    struct sockaddr_in server; // 服务器地址信息
    struct sockaddr_in client; // 客户端地址信息
    socklen_t addrlen;
    
    // 创建套接字描述符
    if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        perror("socket() error. Failed to initiate a socket");
        return 0;
    }
 
    int opt = SO_REUSEADDR;
    setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

    bzero(&server, sizeof(server));
    server.sin_family = AF_INET;
    server.sin_port = htons(PORT);
    server.sin_addr.s_addr = htonl(INADDR_ANY);

    // 将地址 server 绑定到套接字 listenfd 上
    if(bind(listenfd, (struct sockaddr *)&server, sizeof(server)) == -1) {
        perror("Bind() error.");
        return 0;
    }
    
    // 将套接字设置为监听模式,队列长度为 1
    if(listen(listenfd, BACKLOG) == -1) {
        perror("listen() error. \n");
        return 0;
    }

    addrlen = sizeof(client);
    while(1) {
        // 取出一个客户端请求进行连接
        if((connectfd = accept(listenfd,(struct sockaddr *)&client, &addrlen)) == -1) {
            printf("accept() error. \n");
            break;
        }

        printf("The client's ip : %s, port %d\n",inet_ntoa(client.sin_addr),htons(client.sin_port));
        
        // 与客户端通信
        char str[] = "Hello Client, I'm Server!\n";
        while(1) {
            int iret = recv(connectfd, buf, MAXRECVLEN, 0);
            if(iret > 0) {
                printf("%s\n",buf);
            } else {
                close(connectfd);
                break;
            }
            send(connectfd, str, sizeof(str), 0); 
        }
    }
    // 关闭 socket
    close(listenfd); 
    return 0;
}

클라이언트 코드 :

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdbool.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

#define PORT 3322  //服务器端口

#define MAXDATASIZE 100

int main(int argc, char *argv[])
{
    int sockfd, num;
    char buf[MAXDATASIZE];
    struct hostent *host;
    struct sockaddr_in server;
    
    // 参数检查
    if (argc != 2) {
        printf("Usage: %s <IP Address>\n",argv[0]);
        return 0;
    }
    
    if((host = gethostbyname(argv[1])) == NULL) {
        printf("gethostbyname() error\n");
        return 0;
    }
    
    // 创建套接字
    if((sockfd = socket(AF_INET,SOCK_STREAM, 0))==-1) {
        printf("socket() error\n");
        return 0;
    }

    bzero(&server,sizeof(server));
    server.sin_family = AF_INET;
    server.sin_port = htons(PORT);
    server.sin_addr = *((struct in_addr *)host->h_addr);

    // 与服务器建立连接
    if(connect(sockfd, (struct sockaddr *)&server, sizeof(server)) == -1) {
        printf("connect() error\n");
        return 0;
    }
    
    // 与服务器进行通信
    char str[] = "Hello Server, I'm Client!\n";
    while(true) {
        if((num = send(sockfd,str,sizeof(str),0)) == -1) {
            printf("send() error\n");
            break;
        }

        if((num = recv(sockfd,buf,MAXDATASIZE,0)) == -1) {
            printf("recv() error\n");
            break;
        }
        buf[num-1]='\0';
        printf("%s\n", buf);
        sleep(3);
    }

    // 关闭套接字
    close(sockfd);
    return 0;
}

Makefile :

all: client server

client: client.c
	gcc -o client client.c

server: server.c 
	gcc -o server server.c

clean:
	rm -rf client server

컴파일 및 실행, 호스트와의 통신 결과 :

그림 3 동일한 시스템과의 통신

서버와 클라이언트가 모두 로컬 인 경우 바인딩 포트 대신 공유 소켓 파일을 사용하여 통신 할 수 있습니다. 

다른 호스트 간의 통신 :

 

그림 4 원격 통신 서버
그림 5 원격 통신 클라이언트

 

네, 요약

이상은 네트워크 통신이 소켓을 통해 수행되는지를 설명하는 응용 관점에서 더 심도있는 관점에서 설명 할 시간이있을 것입니다.

다섯, 참고 문헌

[1]  https://www.cnblogs.com/langren1992/p/5101380.html

[2]  https://blog.csdn.net/tanzongbiao/article/details/82344074

[3]  https://blog.csdn.net/wjy741223284/article/details/98513237

추천

출처blog.csdn.net/u011074149/article/details/113275450