【操作系统】Linux之网络编程(UDP)(头歌作业)

第1关:UDP套接字创建与端口绑定

cpp 复制代码
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>

/************************
 * port: 需要绑定的端口号
 * 返回值: 调用成功返回0,否则返回-1
*************************/
int UDPSocket(unsigned short port)
{
	int ret = -1;
	/********** BEGIN **********/
	int sockfd;
    struct sockaddr_in server_addr;
    // 创建UDP套接字
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd == -1)
    {
        printf("创建UDP套接字失败: %s\n", strerror(errno));
        return -1;
    }

    // 初始化服务器地址结构体
    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);

    // 绑定端口
    ret = bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
    if (ret == -1)
    {
        printf("绑定端口失败: %s\n", strerror(errno));
        close(sockfd);
        return -1;
    }

    ret = 0;
	
	/********** END **********/
	
	return ret;
}

第2关:UDP数据传送

cpp 复制代码
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>

#define PORT 8888

int main()
{
	int sockfd;
	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if(sockfd == -1)
	{
		return -1;
	}
	struct sockaddr_in addr;
	bzero(&addr, sizeof(addr));    //清空
	addr.sin_family = AF_INET;
	addr.sin_port = htons(PORT);
	addr.sin_addr.s_addr = htonl(INADDR_ANY);
	//与PORT端口进行绑定
	if(bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
	{
		return -1;
	}
	
	char data[100];
	//接收客户端传来的数据,并打印出来(提示:换行打印)
	//同时将接收到的数据原样发送给客户端
	//当接收到"exit"字符串时,退出当前程序,不打印出"exit"字符串
	//提示:在每次接收字符串前要将存放字符串的变量清空
	/********** BEGIN **********/
	struct sockaddr_in clientAddr;
    socklen_t clientAddrLen = sizeof(clientAddr);
    while (1)
    {
        // 每次接收前清空存放字符串的变量
        memset(data, 0, sizeof(data));

        ssize_t recvLen = recvfrom(sockfd, data, sizeof(data), 0, (struct sockaddr *)&clientAddr, &clientAddrLen);
        if (recvLen == -1)
        {
            printf("接收数据失败: %s\n", strerror(errno));
            continue;
        }
        else if (recvLen > 0)
        {
            // 去掉字符串末尾可能的换行符等空白字符
            while (data[recvLen - 1] == '\n' || data[recvLen - 1] == '\r' || data[recvLen - 1] == '\t' || data[recvLen - 1] == ' ')
            {
                data[recvLen - 1] = '\0';
                recvLen--;
            }

            if (strcmp(data, "exit") == 0)
            {
                break;
            }

            // 换行打印接收到的数据
            printf("%s\n", data);

            // 将接收到的数据原样发送给客户端
            ssize_t sendLen = sendto(sockfd, data, recvLen, 0, (struct sockaddr *)&clientAddr, clientAddrLen);
            if (sendLen == -1)
            {
                printf("发送数据失败: %s\n", strerror(errno));
            }
        }
    }
	
	/********** END **********/

	close(sockfd);
	
	return 0;
}

第3关:项目实战

cpp 复制代码
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

//定义数据块大小
char data[16];
//定义服务器端口和服务器地址
#define PORT 8889
#define SERVER_IP "127.0.0.1"

int main(int argc, char *argv[])
{
	int sockfd;
	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if(sockfd == -1)
	{
		return -1;
	}
	struct sockaddr_in servAddr;
	int servAddrLen = sizeof(servAddr);
	bzero(&servAddr, sizeof(servAddr));
	servAddr.sin_family = AF_INET;
	servAddr.sin_port = htons(PORT);
	servAddr.sin_addr.s_addr = inet_addr(SERVER_IP);
	
	//由用户传入的要下载文件的名称
	char *downLoadFileName = argv[1];
	printf("%s\n", argv[1]);
	//先在本地创建要下载的文件
	int fd = fd = open(downLoadFileName, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
	//向服务器发送要上传文件的名称
	sendto(sockfd, downLoadFileName, strlen(downLoadFileName), 0, (struct sockaddr *)&servAddr, servAddrLen); 
	
    /********** BEGIN **********/
	char ack[16];
    int recvLen;

    // 循环接收服务器发送的数据块
    while (1)
    {
        // 接收服务器发送的数据块
        recvLen = recvfrom(sockfd, data, sizeof(data), 0, (struct sockaddr *)&servAddr, &servAddrLen);
        if (recvLen == -1)
        {
            printf("接收数据失败: %s\n", strerror(errno));
            continue;
        }

        // 根据数据块类型判断是否下载完成
        if (data[0] == 'e')
        {
            // 下载完成,关闭文件并退出程序
            close(fd);
            break;
        }
        else if (data[0] == 'c')
        {
            // 数据块为文件内容,将内容写入本地文件
            write(fd, &(data[1]), recvLen - 1);
        }

        // 向服务器发送接收确认请求
        sendto(sockfd, "OK", strlen("OK"), 0, (struct sockaddr *)&servAddr, servAddrLen);

        // 清空数据块数据部分(除了类型标识字节)
        memset(&(data[1]), 0, sizeof(data) - 1);
    }
	
	/********** END **********/
	
	close(sockfd);
	
	return 0;
}
相关推荐
Charary20 分钟前
字符设备驱动开发与杂项开发
linux·驱动开发
孤寂大仙v1 小时前
【Linux笔记】理解文件系统(上)
linux·运维·笔记
钢板兽2 小时前
Java后端高频面经——JVM、Linux、Git、Docker
java·linux·jvm·git·后端·docker·面试
byxdaz2 小时前
NVIDIA显卡驱动、CUDA、cuDNN 和 TensorRT 版本匹配指南
linux·人工智能·深度学习
别说我什么都不会2 小时前
当OpenHarmony遇上OpenEuler
操作系统·嵌入式·harmonyos
大白的编程日记.3 小时前
【Linux学习笔记】Linux基本指令分析和权限的概念
linux·笔记·学习
努力学习的小廉3 小时前
深入了解Linux —— 调试程序
linux·运维·服务器
努力学习的小廉3 小时前
深入了解Linux —— git三板斧
linux·运维·git
只做开心事3 小时前
Linux网络之数据链路层协议
linux·服务器·网络
钡铼技术物联网关3 小时前
ARM嵌入式低功耗高安全:工业瘦客户机的智慧城市解决方案
linux·安全·智慧城市