网络编程2

网络编程2

2022-12-12
c语言
  • 网络编程练习程序

根据域名获取IP地址 #

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        printf("Usage: %s <hostname>\n", argv[0]);
        exit(1);
    }
    struct hostent *host = gethostbyname(argv[1]);
    if (host == 0)
    {
        printf("Get host error\n");
        exit(1);
    }
    printf("Official name: %s\n", host->h_name);
    for (int i = 0; host->h_aliases[i]; i++)
    {
        printf("Alias %d: %s\n", i + 1, host->h_aliases[i]);
    }
    //获取ip地址列表
    for (int i = 0; host->h_addr_list[i]; i++)
    {
        printf("Ip addr %d: %s\n", i + 1, inet_ntoa(*(struct in_addr*)host->h_addr_list[i]));
    }
    return 0;
}

UDP服务端和客户端 #

  • 服务端
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define BUF_SIZE 1024

void error_handling(char *message);

int main(int argc, char *argv[])
{
    int port = 5140;
    if (argc == 2)
    {
        port = atoi(argv[1]);
    }
    //创建socket
    int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
    int option = 1;
    socklen_t option_len = sizeof(option);
    //设置time_wait
    setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &option, option_len);
    if (sock == -1)
    {
        error_handling("socket() error");
    }

    //绑定端口,接收数据
    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    server_addr.sin_port = htons(port);
    if (bind(sock, (struct sockaddr *)&server_addr, sizeof(server_addr))) 
    {
        error_handling("bind() error");
    }

    struct sockaddr_in client_addr;
    int client_addr_len = sizeof(client_addr);
    char buf[BUF_SIZE];
    while (1)
    {
        ssize_t recv_num = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *)&client_addr, &client_addr_len);
        if (recv_num == -1) 
        {
            error_handling("recvfrom() error");
        }
        buf[recv_num] = 0;
        printf("%s\n", buf);
    }
    close(sock);
    return 0;
}

void error_handling(char *message)
{
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}
  • 客户端
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

void error_handling(char *message);

int main(int argc, char *argv[])
{
    int port = 5140;
    char *ip = "127.0.0.1";
    char *message = "hello world";
    if (argc == 4)
    {
        ip = argv[1];
        port = atoi(argv[2]);
        message = argv[3];
    }
    int sock = socket(PF_INET, SOCK_DGRAM, 0);
    if (sock == -1)
    {
        error_handling("socket() error");
    }

    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr(ip);
    addr.sin_port = htons(port);
    //如果要与同一主机进行长时间通信时,可以将UDP套接字变为已连接套接字会提高效率
    sendto(sock, message, strlen(message), 0, (struct sockaddr *)&addr, sizeof(addr));
    close(sock);
    return 0;
}

void error_handling(char *message)
{
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}
  • 客户端2(已连接套接字)
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define BUF_SIZE 1024

void error_handling(char *message);

int main(int argc, char *argv[])
{
    int port = 5140;
    if (argc == 2)
    {
        port = atoi(argv[1]);
    }
    //创建socket
    int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
    int option = 1;
    socklen_t option_len = sizeof(option);
    //设置time_wait
    setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &option, option_len);
    if (sock == -1)
    {
        error_handling("socket() error");
    }

    //绑定端口,接收数据
    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    server_addr.sin_port = htons(port);
    if (bind(sock, (struct sockaddr *)&server_addr, sizeof(server_addr))) 
    {
        error_handling("bind() error");
    }

    struct sockaddr_in client_addr;
    int client_addr_len = sizeof(client_addr);
    char buf[BUF_SIZE];
    while (1)
    {
        ssize_t recv_num = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *)&client_addr, &client_addr_len);
        if (recv_num == -1) 
        {
            error_handling("recvfrom() error");
        }
        buf[recv_num] = 0;
        printf("%s\n", buf);
    }
    close(sock);
    return 0;
}

void error_handling(char *message)
{
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}

多进程 #

僵尸进程 #

  • 进程执行完成后,应当被销毁,但有时这些进程会变成僵尸进程,占用系统资源。而子进程的返回值都会传递给操作系统,而操作系统并不会销毁子进程,直到把这些值传给该子进程的父进程。而操作系统不会主动把这些值传给父进程,父进程需要需要负责回收子进程。

  • 可以向操作系统注册,当子进程停止时,调用对应的方法。
struct sigaction
{
        void (*sa_handler)(int);	//处理信号处理函数的指针值
	sigset_ sa_mask;
	int sa_flags;
}

echo服务端(程序) #

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#define BUF_SIZE 1024
void error_handling(char *message);
void read_child_proc(int sig);

int main(int argc, char *argv[])
{
    int port = 8899;
    if (argc == 2)
    {
        port = atoi(argv[1]);
    }

    //当子程序结束时,如何去处理
    struct sigaction act;
    act.sa_flags = 0;
    act.sa_handler = read_child_proc;
    sigemptyset(&act.sa_mask);
    int state = sigaction(SIGCHLD, &act, 0);

    struct sockaddr_in server_addr, client_addr;
    int server_sock = socket(PF_INET, SOCK_STREAM, 0);
    int option = 1;
    //设置time_wait时端口可以被重用
    setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));

    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    server_addr.sin_port = htons(port);
    if (bind(server_sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1)
    {
        error_handling("bind() error");
    }
    if (listen(server_sock, 5) == -1)
    {
        error_handling("listen() error");
    }
    while (1)
    {
        int client_addr_size = sizeof(client_addr);
        int client_sock = accept(server_sock, (struct sockaddr *)&client_addr, &client_addr_size);
        if (client_sock == -1)
        {
            continue;
        }
        else
        {
            printf("client connected...\n");
        }
        int pid = fork();
        if (pid == 0)
        { /*子进程*/
            close(server_sock);
            int str_len;
            char buf[BUF_SIZE];
            while((str_len = read(client_sock, buf, BUF_SIZE)) != 0)
            {
                write(client_sock, buf, str_len);
                buf[str_len] = 0;
                printf("client msg: %s\n", buf); 
            }
            sleep(5);
            printf("client disconnected...\n");
            close(client_sock);
            return 0;  
        }
        else
        {
            close(client_sock);
        }
    }
    close(server_sock);
    return 0;
}

/**
 * 子进程停止时调用
*/
void read_child_proc(int sig)
{
    pid_t pid;
    int status;
    //解决僵尸进程
    pid = waitpid(-1, &status, WNOHANG);
    printf("removed pid: %d\n", pid);
}

void error_handling(char *message)
{
    fputs(message, stderr);
    fputc('\n', stderr);
    exit(1);
}

管道(程序) #

#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>

#define BUF_SIZE 1024

void read_child_status(int sig)
{
    pid_t pid;
    int status;
    pid = waitpid(pid, &status, WNOHANG);
    printf("remove pid: %d, status: %d, sig: %d\n", pid, status, sig);
}

int main(int argc, char * argv[])
{
    //避免僵尸进程
    struct sigaction act;
    act.sa_flags = 0;
    sigemptyset(&act.sa_mask);
    act.sa_handler = read_child_status;
    sigaction(SIGCHLD, &act, 0);

    //管道
    int fds[2];
    pipe(fds);

    int pid = fork();
    if (pid == 0)
    {
        char msg[] = "hello world";
        write(fds[1], msg, strlen(msg));
    }
    else 
    {
        char buf[BUF_SIZE];
        int str_len = read(fds[0], buf, BUF_SIZE);
        buf[str_len] = 0;
        printf("read from child: %s \n", buf);
        sleep(2);
    }
}