【操作系统】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;
}
相关推荐
许白掰1 小时前
Linux入门篇学习——Linux 工具之 make 工具和 makefile 文件
linux·运维·服务器·前端·学习·编辑器
longze_75 小时前
Ubuntu连接不上网络问题(Network is unreachable)
linux·服务器·ubuntu
Dirschs5 小时前
【Ubuntu22.04安装ROS Noetic】
linux·ubuntu·ros
qianshanxue115 小时前
ubuntu 操作记录
linux
AmosTian8 小时前
【系统与工具】Linux——Linux简介、安装、简单使用
linux·运维·服务器
这我可不懂11 小时前
Python 项目快速部署到 Linux 服务器基础教程
linux·服务器·python
车车不吃香菇11 小时前
java idea 本地debug linux服务
java·linux·intellij-idea
tan77º11 小时前
【Linux网络编程】Socket - TCP
linux·网络·c++·tcp/ip
kfepiza12 小时前
Linux的`if test`和`if [ ]中括号`的取反语法比较 笔记250709
linux·服务器·笔记·bash
CodeWithMe12 小时前
【Note】《深入理解Linux内核》 第十九章:深入理解 Linux 进程通信机制
linux·运维·php