Linux网络编程之TCP文件传输

这篇具有很好参考价值的文章主要介绍了Linux网络编程之TCP文件传输。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1. 要求

在Linux环境下,编程实现文件的上传和下载,即客户端可以发送文件给服务器,服务器将文件写到服务器端文件系统中;客户端请求下载文件时服务器读取文件内容,发送给客户端,客户端接收内容并写入本地文件。要求

(1)源代码格式化良好并适当注释;

(2)除上述核心功能外,尽量完善程序,比如使其使用方便等;

(3)提交报告,报告中包括程序源代码和测试效果截图。

2. 基本设计思路

2.1 服务器和客户端的socket连接

服务器通过对socket进行监听listen(),等待客户端的主动连接connect()。

服务器在建立连接后通过pork()函数赋值进程,使子进程关闭服务器的socket监听并向客户端提供服务;父进程则继续监听socket,继续与其他客户端进行连接。

  • 为什么客户端connect前不需要进行bind?

操作系统会自动选择一个可用的本地 IP 地址和端口号来作为客户端套接字的地址,并将这个地址作为连接请求的源地址发送给服务器。这个过程称为“自动绑定”

2.2 客户端的服务请求

在建立了与服务端的socket连接后,客户端通过向服务端发送相关的指令来请求相对应的服务。

通过输入指令发送到服务端,使服务端解析指令,并向客户端返回相对应的数据包。客户端接收并解析数据包来获取相关信息。

2.3 服务端的服务提供

服务端在接收到客户端发来的指令后,根据指令的不同,执行不同的操作。

若接收到客户端下载文件的指令,则将相对应的文件封装成数据包,发送到客户端。

若接收到客户端上传文件的指令,则调用recv()函数来接收由客户端发送过来的数据包,并解析内容写入文本中。

3. 源代码

3.1 server.cpp
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<fcntl.h>
#include<dirent.h>
#include<string>
#include<vector>

#define port 8888
#define backlog 5
#define MAXBUFF 4096
#define MAXNAMELEN 100

void process_con_server(int s);
void analyzeCommand(char *command, int s);
void sendMessage(int s);
char** splitString(char* str, int& num);
void sendFile(int s, char *fname);
void recvFile(int s, char *fname);

/*文件信息*/
typedef struct FileMess{
    unsigned long fileLen;
    char fileName[100];
} FileMess;

/*数据包*/
typedef struct DataPack{
    char type;     //'D'表示数据,'M'表示文件信息, 'E'表示错误数据包
    int packSize;   //整个数据包的大小
    char content[MAXBUFF];  //数据包携带数据缓冲区
    int contentLen;     //数据包中数据的长度
    unsigned long position;    //数据在文件中的字节位置
    FileMess fileMess;      //文件信息
} DataPack;

/*目录信息数据包*/
typedef struct DirPack{
    int flag;      //标志位,1表示包含目录文件名,0表示结束目录发送的空数据包
    char content[100];
} DirPack;

int main(int argc, char *argv[]){
    int ss, sc;
    struct sockaddr_in server_addr;
    struct sockaddr_in client_addr;
    int err;
    pid_t pid;
    
    /*创建套接字socket*/
    ss = socket(AF_INET, SOCK_STREAM, 0);
    if(ss < 0){
        printf("Create Socket error!!!\n");
        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);

    /*绑定服务器地址到套接字socket*/
    err = bind(ss, (struct sockaddr*)&server_addr, sizeof(server_addr));
    if(err < 0){
        printf("Bind server address error!!!\n");
        return -1;
    }
     
    /*启动监听*/
    err = listen(ss, backlog);  //设置最大排队数量为backlog
    if(err < 0){
        printf("Start listenning failure!!!\n");
        return -1;
    }

    /*服务器建立连接和提供服务*/
    while(1){
        socklen_t addrlen = sizeof(struct sockaddr);
        /*接收来自客户端client的套接字socket*/
        sc = accept(ss, (struct sockaddr*)&client_addr, &addrlen);
        if(sc < 0){
            printf("accept error!\n");
            continue;   //跳过创建子进程,避免浪费
        }

        /*创建新进程继续处理排队中的客户端连接*/
        pid = fork();
        if(pid == 0){       //父进程的pid永远不为0,未初始化时为随机值
            close(ss);                  //在子进程中关闭服务器监听
            process_con_server(sc);     //向客户端提供服务
        }
        else{
            close(sc);
            
        }
    }
    return 0;
}

/*服务器处理与客户端的连接服务*/
void process_con_server(int s){
    ssize_t size;
    char buffer[1024];      //使用1024bytes的缓冲区来接收用户指令

    while(1){
        memset(buffer, 0, sizeof(buffer));
        
        size = recv(s, buffer, sizeof(buffer), 0);   //会读取回车\n
        if(size == 0)
            return;

        write(STDOUT_FILENO, buffer, size);
        analyzeCommand(buffer, s);  //解析用户指令
    }
    close(s);
}


/*解析客户端指令*/
void analyzeCommand(char *command, int s){
    int substrNum;
    char** substr = splitString(command, substrNum);
    
    /*显示可下载的文件列表, 将列表通过socket传输到客户端*/
    if(!strcmp(substr[0], "ls\n")){
        sendMessage(s);
    }
    /*下载指定文件*/
    else if(!strcmp(substr[0], "download")){
        sendFile(s, substr[1]);
    }
    /*接收来自客户端上传的文件*/
    else if(!strcmp(substr[0], "send")){
        recvFile(s, substr[1]);
    }
    else{
        char *mes = "Please write down the right command!!!\n";
        write(s, mes, strlen(mes));
    }
}

/*以一个或多个空格分割字符串*/
/*返回值:指针数组*/
/*一般输入的指令是 指令+文件名的形式  例如"send test.txt"*/
char** splitString(char* str, int& num) {
    int len = strlen(str);
    char** result = new char*[len];

    int count = 0;
    int start = 0;
    /*遍历分割字符串*/
    for (int i = 0; i < len; ++i) {
        if (str[i] == ' ') {
            if (i - start > 0) {
                int size = i - start;
                result[count] = new char[size + 1];     //size+1是为了尾部添加'\0'作为截至
                strncpy(result[count], &str[start], size);
                result[count][size] = '\0';
                ++count;
            }
            start = i + 1;
        }
    }

    /*若字符串不以空格结尾,则需要将字符串尾部添加*/
    if (len - start > 0) {
        int size = len - start;
        result[count] = new char[size + 1];
        strncpy(result[count], &str[start], size);
        result[count][size] = '\0';
        ++count;
    }

    num = count;
    return result;
}

/*服务器向客户端发送文件,即客户端下载文件*/
void sendFile(int s, char *fname){  //fname含有'\n'回车
    DataPack dataPack;
    char path[100] = "./resources/";
    //去除字符串fname末尾的回车
    char *fName = (char*)malloc(strlen(fname)-1);   
    strncpy(fName, fname, strlen(fname)-1);
    //拼接文件名与资源路径得到文件路径
    strncat(path, fName, strlen(fname)-1);

    //判断用户获取的资源文件是否存在
    int st = access(path, F_OK);
    if(-1 == st){
        /*设置错误信息,并以错误信息类型发送数据包*/
        dataPack.type = 'E';
        dataPack.packSize = sizeof(DataPack);
        char *buffer = "The file isn't exist!!!\n";
        strncpy(dataPack.content, buffer, strlen(buffer));
        dataPack.contentLen = strlen(buffer);
        dataPack.position = 0;
        send(s, &dataPack, dataPack.packSize, 0);
        return;
    }

    /*获取并发送文件信息*/
    struct stat statbuf;
    stat(path, &statbuf);
    dataPack.type = 'M';
    dataPack.packSize = sizeof(DataPack);
    dataPack.fileMess.fileLen = statbuf.st_size;
    strncpy(dataPack.fileMess.fileName, fName, strlen(fName));
    unsigned long sRe = send(s, &dataPack, dataPack.packSize, 0);
    printf("成功发送文件信息数据包!\n");
    

    /*发送文件内容*/
    unsigned long sendedCount = 0;      //记录已发送的数据大小
    int fd = open(path, O_RDONLY);     //打开文件
    while(sendedCount < statbuf.st_size){
        //构造文件内容数据包
        DataPack filedata;
        memset(&filedata, 0, sizeof(DataPack));
        unsigned long readBytes = read(fd, filedata.content, MAXBUFF);
        filedata.contentLen = readBytes;
        filedata.type = 'D';
        filedata.packSize = sizeof(DataPack);
        filedata.position = sendedCount;

        unsigned long sDa = send(s, &filedata, filedata.packSize, 0);
        if(sDa > 0){
            sendedCount += filedata.contentLen;
        }
        printf("成功发送数据:%ld bytes\n", sendedCount);
    }

    //构造结束标志数据包,标志文件传输完毕
    memset(&dataPack, 0, sizeof(DataPack));
    dataPack.type = 'E';
    send(s, &dataPack, sizeof(DataPack), 0);
    close(fd);
    return;        
}

/*服务器接收文件,即客户端上传文件*/
void recvFile(int s, char *fname){
    
    unsigned long fileSize = 0;     //记录接收文件的大小
    unsigned long recvedCount = 0;  //记录已接收的数据量大小
    int fd = 0;
    DataPack *dataPack = (DataPack *)malloc(sizeof(DataPack));
    while(1){
        memset(dataPack, 0, sizeof(DataPack));
        unsigned long recvBytes = recv(s, dataPack, sizeof(DataPack), 0);

        //'E'类型的数据包为错误数据包
        //在文件传输完成后,会发送一个空内容(content)的错误数据包,表示文件传输完成
        //也可以选择重新定义一个新的类型的数据包作为结束数据包类型
        if(dataPack->type == 'E'){   //该数据包为错误数据包
            write(STDOUT_FILENO, dataPack->content, dataPack->contentLen);
            break;
        }

        //'M'类型的数据包为文件信息数据包,根据相应的信息创建文件
        else if(dataPack->type == 'M'){
            char path[200] = "./upload/";
            strcat(path, dataPack->fileMess.fileName);
            //无论什么时候都创新创建文件
            fd = open(path, O_CREAT | O_TRUNC | O_RDWR, S_IRWXU);
            fileSize = dataPack->fileMess.fileLen;
        }
        
        //'D'类型数据包为文件内容数据包,解析数据包内容,并写入相应文件的相应位置
        else if(dataPack->type = 'D'){
            lseek(fd, recvedCount, SEEK_SET);
            write(fd, dataPack->content, dataPack->contentLen);
            recvedCount += dataPack->contentLen;
       }
    }
    if (fd != 0){
        close(fd);      //关闭文件描述符
    }
}

void sendMessage(int s){
    DIR *dirp;
    struct dirent *direntp;
    int count = 0;
    DirPack *dirpack = (DirPack *)malloc(sizeof(DirPack));
    memset(dirpack, 0, sizeof(DirPack));
    dirpack->flag = 1;
    // 打开当前目录
    dirp = opendir("./resources/");
    // 读取目录内容
    while ((direntp = readdir(dirp)) != NULL) {
        // 忽略当前目录和父目录
        if (strcmp(direntp->d_name, ".") == 0 || strcmp(direntp->d_name, "..") == 0) {
            continue;
        }

        // 将文件名发送到客户端中
        char *dirfName = strdup(direntp->d_name);   //获取文件名
        strncpy(dirpack->content, dirfName, strlen(dirfName));
        send(s, dirpack, sizeof(DirPack), 0);
        // 清空数据包的内容
        memset(dirpack->content, 0, sizeof(dirpack->content));
    }

    //构造结束数据包
    dirpack->flag = 0;
    send(s, dirpack, sizeof(DirPack), 0);

    // 关闭目录
    closedir(dirp);
}

3.2 client.cpp
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/socket.h>
#include<fcntl.h>
#include<unistd.h>
#include<arpa/inet.h>

#define port 8888
#define MAXBUFF 4096

void process_con_client(int s);             //处理与服务器的连接服务
char** splitString(char* str, int& num);    //以一个或多个空格分割字符串
void analyzeCommand(char *command, int s);  //解析用户输入的命令    
void recvFile(int s, char *fname);          //接收来自服务器的文件数据包
void sendFile(int s, char *fname);          //向服务器上传文件
void recvMessage(int s);                    //接收可下载文件目录信息

/*文件信息*/
typedef struct FileMess{
    unsigned long fileLen;
    char fileName[100];
} FileMess;

/*文件数据包*/
typedef struct DataPack{
    char type;     //'D'表示数据,'M'表示文件信息, 'E'表示错误数据包
    int packSize;   //整个数据包的大小
    char content[MAXBUFF];  //数据包携带数据缓冲区
    int contentLen;     //数据包中数据的长度
    unsigned long position;    //数据在文件中的字节位置
    FileMess fileMess;      //文件信息
} DataPack;

/*目录信息数据包*/
typedef struct DirPack{
    int flag;      //标志位,1表示包含目录文件名,0表示结束目录发送的空数据包
    char content[100];
} DirPack;

int main(int argc, char *argv[]){
    int s;
    struct sockaddr_in server_addr;
    int err;

    /*创建套接字socket*/
    s = socket(AF_INET, SOCK_STREAM, 0);
    if(s < 0){
        printf("Create socket error!!!\n");
        return -1;
    }

    /*设置连接服务器IP地址和端口号*/
    memset(&server_addr, 0, sizeof(struct sockaddr_in));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(port);
    inet_pton(AF_INET, argv[1], &server_addr.sin_addr);

    /*为什么客户端connect前不需要进行bind?*/
    /*操作系统会自动选择一个可用的本地 IP 地址和端口号来作为客户端套接字的地址,
    并将这个地址作为连接请求的源地址发送给服务器。这个过程称为“自动绑定”*/

    /*连接服务器*/
    err = connect(s, (struct sockaddr*)&server_addr, sizeof(struct sockaddr));
    if(err < 0){
        printf("Connect error!!!\n");
        return -1;
    }
    process_con_client(s);  //请求服务
    close(s);       //关闭连接
    return 0;
}

/*处理客户端与服务器的连接*/
void process_con_client(int s){
    ssize_t size = 0;
    char buffer[1024];

    //反复处理用户输入的命令
    while(1){
        memset(buffer, 0, sizeof(buffer));
        size = read(STDIN_FILENO, buffer, 1024);
        if(size > 0){
            write(s, buffer, size);
            analyzeCommand(buffer, s);
        }
    }
    close(s);
}


/*以一个或多个空格分割字符串*/
/*返回值:指针数组*/
/*num:传出参数,字符串分割成的子串个数*/
char** splitString(char* str, int& num) {
    int len = strlen(str);
    char** result = new char*[len];

    int count = 0;
    int start = 0;
    /*遍历分割字符串*/
    for (int i = 0; i < len; ++i) {
        if (str[i] == ' ') {
            if (i - start > 0) {
                int size = i - start;
                result[count] = new char[size + 1];     //size+1是为了尾部添加'\0'作为截至
                strncpy(result[count], &str[start], size);
                result[count][size] = '\0';
                ++count;
            }
            start = i + 1;
        }
    }

    /*若字符串不以空格结尾,则需要将字符串尾部添加*/
    if (len - start > 0) {
        int size = len - start;
        result[count] = new char[size + 1];
        strncpy(result[count], &str[start], size);
        result[count][size] = '\0';
        ++count;
    }

    num = count;
    return result;
}

/*解析客户端用户输入的指令*/
void analyzeCommand(char *command, int s){
    int substrNum;
    char** substr = splitString(command, substrNum);

    /*判断用户输入的指令是否符合格式*/
    /*此处仅提供三种指令,ls、download [filename]、send [filename]*/
    if(substrNum > 2){
        char *buffer = "The format of command is error!!!\n";
        write(STDOUT_FILENO, buffer, strlen(buffer));
    }
    /*显示可下载的文件列表, 接收来自服务器传输过来的信息*/
    if(!strcmp(substr[0], "ls\n")){
        recvMessage(s);
    }
    /*下载指定文件*/
    if(!strcmp(substr[0], "download")){
        recvFile(s, substr[1]);
    }
    /*上传指定的文件到服务器*/
    if(!strcmp(substr[0], "send")){
        sendFile(s, substr[1]);
    }
}

/*执行文件下载命令,接收服务器发来的数据包*/
void recvFile(int s, char *fname){
    
    unsigned long fileSize = 0;     //记录接收文件的大小
    unsigned long recvedCount = 0;  //记录已接收的数据量大小
    int fd = 0;
    DataPack *dataPack = (DataPack *)malloc(sizeof(DataPack));  //动态分配内存
    while(1){
        memset(dataPack, 0, sizeof(DataPack));
        unsigned long recvBytes = recv(s, dataPack, sizeof(DataPack), 0);

        //'E'类型的数据包为错误数据包
        //在文件传输完成后,会发送一个空内容(content)的错误数据包,表示文件传输完成
        //也可以选择重新定义一个新的类型的数据包作为结束数据包类型
        if(dataPack->type == 'E'){
            write(STDOUT_FILENO, dataPack->content, dataPack->contentLen);
            break;
        }
        
        //'M'类型的数据包为文件信息数据包,根据相应的信息创建文件
        else if(dataPack->type == 'M'){
            char path[200] = "./download/";
            char *fName = (char*)malloc(strlen(fname)-1);   
            strncpy(fName, fname, strlen(fname)-1);   
            strncat(path, fName, strlen(fname)-1);
            //无论什么时候都创新创建文件
            fd = open(path, O_CREAT | O_TRUNC | O_RDWR, S_IRWXU);
            fileSize = dataPack->fileMess.fileLen;
        }
        
        //'D'类型数据包为文件内容数据包,解析数据包内容,并写入相应文件的相应位置
        else if(dataPack->type = 'D'){
            lseek(fd, recvedCount, SEEK_SET);
            write(fd, dataPack->content, dataPack->contentLen);
            recvedCount += dataPack->contentLen;
       }
    }
    if (fd != 0){
        close(fd);      //关闭文件描述符
    }
}

/*接收服务器发来的可下载文件目录数据包*/
void recvMessage(int s){
    DirPack *dirpack = (DirPack *)malloc(sizeof(DirPack));      //动态分配内存
    memset(dirpack, 0, sizeof(DirPack));
    int count = 0;
    while(1){
        recv(s, dirpack, sizeof(DirPack), 0);
        ++count;
        //接收完毕目录后会发现一个flag标志为0的数据包,表示目录数据包发送完毕
        if(dirpack->flag == 0){
            memset(dirpack, 0, sizeof(DirPack));    
            break;
        }
        write(STDOUT_FILENO, dirpack->content, sizeof(dirpack->content));

        //排布显示
        if(count%4 == 0){
            write(STDOUT_FILENO, "\n", 1);
        }
        else {
            write(STDOUT_FILENO, "\t", 1);
        }
        memset(dirpack, 0, sizeof(DirPack));
    }
    free(dirpack);
}

/*执行上传文件命令,向服务器发送文件信息和内容数据包*/
void sendFile(int s, char *fname){  //fname含有'\n'回车
    DataPack dataPack;

    //去除字符串fname末尾的回车
    char *fName = (char*)malloc(strlen(fname)-1);   
    strncpy(fName, fname, strlen(fname)-1);

    //判断是否存在相应名称的文件
    int st = access(fName, F_OK);
    if(-1 == st){
        /*设置错误信息,并以错误信息类型发送数据包*/
        dataPack.type = 'E';
        dataPack.packSize = sizeof(DataPack);
        char *buffer = "The file isn't exist!!!\n";
        strncpy(dataPack.content, buffer, strlen(buffer));
        dataPack.contentLen = strlen(buffer);
        dataPack.position = 0;
        send(s, &dataPack, dataPack.packSize, 0);
        return;
    }
    

    /*获取并发送文件信息*/
    struct stat statbuf;
    stat(fName, &statbuf);
    dataPack.type = 'M';
    dataPack.packSize = sizeof(DataPack);
    dataPack.fileMess.fileLen = statbuf.st_size;
    strncpy(dataPack.fileMess.fileName, fName, strlen(fName));
    unsigned long sRe = send(s, &dataPack, dataPack.packSize, 0);
    if(sRe > 0){
        printf("成功发送文件信息数据包!\n");
    }
    

    /*发送文件内容*/
    unsigned long sendedCount = 0;      //记录已发送的数据大小
    int fd = open(fName, O_RDONLY);     //打开文件
    //当发送的数据量小于文件大小时则继续发送数据
    while(sendedCount < statbuf.st_size){

        DataPack filedata;
        memset(&filedata, 0, sizeof(DataPack));
        unsigned long readBytes = read(fd, filedata.content, MAXBUFF);
        filedata.contentLen = readBytes;
        filedata.type = 'D';
        filedata.packSize = sizeof(DataPack);
        filedata.position = sendedCount;

        unsigned long sDa = send(s, &filedata, filedata.packSize, 0);
        if(sDa > 0){
            sendedCount += filedata.contentLen;
            printf("成功发送数据:%ld bytes\n", sendedCount);
        }
        
    }

    /*发送传输结束数据包*/
    memset(&dataPack, 0, sizeof(DataPack));
    dataPack.type = 'E';
    send(s, &dataPack, sizeof(DataPack), 0);
    close(fd);
    return;        
}

4. 结果测试

4.1 g++编译源代码
  • server.cpp
g++ server.cpp -o server

linux socket 传输文件,Linux网络编程,网络,linux,tcp/ip

  • client.cpp
g++ client.cpp -o client

linux socket 传输文件,Linux网络编程,网络,linux,tcp/ip

4.2 相应文件内容
  • 客户端

linux socket 传输文件,Linux网络编程,网络,linux,tcp/ip

  • 服务端

linux socket 传输文件,Linux网络编程,网络,linux,tcp/ip

4.3 运行效果
  • 服务端网络配置

linux socket 传输文件,Linux网络编程,网络,linux,tcp/ip

  • client

linux socket 传输文件,Linux网络编程,网络,linux,tcp/ip

  • server

linux socket 传输文件,Linux网络编程,网络,linux,tcp/ip

运行流程:

  1. 服务端运行server程序,启动监听;客户端启动client程序,主动与服务端建立连接;

  2. 客户端向服务端发送‘ls’指令,服务端收到‘ls’指令后,打印指令,并向客户端提供当前目录下的resources文件夹中所包含的文件目录;

    客户端收到文件目录后,打印文件目录;

  3. 客户端向服务端发送‘download test3.txt’指令,服务端收到‘download test3.txt’指令后,打印指令,并打开resource文件夹中中test3.txt文件,读取内容与文件信息,打包成数据包发送到客户端。

    客户端收到数据包后,解析数据包内容,并在download文件夹中创建相应类型的文件,将数据包的内容写入文件中。

  4. 客户端向服务端发送‘download test2.txt’指令,服务端收到‘download test2.txt’指令后,打印指令,并打开resource文件夹中中test2.txt文件,读取文件信息,打包成数据包发送到客户端;读取内容,发现内容为空,故不发送文件内容数据包。

    客户端收到文件信息数据包,解析数据包内容,并在download文件夹中创建相应类型的文件。由于没有文件内容数据包,此时边不执行文件内容写入操作;

  5. 客户端向服务端发送‘send sdtos.txt’指令,服务端收到‘send sdtos.txt’指令后,打印指令。

    客户端读取当前目录下的sdtos.txt文件的文件信息和文件内容,将其封装成数据包,发送到服务端;

    在收到客户端发送过来的数据包后,在当前目录的upload文件夹中创建相应的文件,并向文件中写入相应的文件内容。

  • 客户端

linux socket 传输文件,Linux网络编程,网络,linux,tcp/ip

  • 服务端

linux socket 传输文件,Linux网络编程,网络,linux,tcp/ip文章来源地址https://www.toymoban.com/news/detail-720871.html

到了这里,关于Linux网络编程之TCP文件传输的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 「网络编程」第二讲:socket套接字(四 - 完结)_ Linux任务管理与守护进程 | TCP协议通讯流程

    「前言」文章是关于网络编程的socket套接字方面的,上一篇是网络编程socket套接字(三),这篇续上篇文章的内容,下面开始讲解!  「归属专栏」网络编程 「主页链接」个人主页 「笔者」枫叶先生(fy) 「枫叶先生有点文青病」「句子分享」 Time goes on and on, never to an 

    2024年02月10日
    浏览(46)
  • 《TCP/IP网络编程》--基于TCP实现字符串对话和文件传输

    主要需求:         服务器端和客户端各传递 1 次字符串,基于 TCP 协议,传递字符串前先以 4 字节整数型方式传递字符串长度,剩余部分为字符串数据; 注:下面的代码基于 Windows 系统实现; 项目链接:Chapter5

    2024年02月09日
    浏览(38)
  • Linux网络编程- 原始套接字(Raw Socket)

    原始套接字(Raw Socket)提供了一种机制,允许应用程序直接访问底层传输协议,绕过操作系统提供的传输层接口。这种套接字通常用于实现新的协议或对现有协议进行低级别的操作。 以下是对原始套接字的详细介绍: 定义与用途 : 原始套接字是直接基于网络层(如IP)的。

    2024年02月07日
    浏览(33)
  • Linux网络编程:socket实现client/server通信

    阅读 UNIX网络编程 卷1:套接字联网API 第3版 的前4个章节,觉得有必要对书籍上的源码案例进行复现,并推敲TCP的C/S通信过程。 📌 测试环境:CentOS7.6 x64 编译server.c 和 client.c gcc server.c -g -std=gnu99 -o server 和 gcc client.c -g -std=gnu99 -o client 运行测试: 📌 server.c仅仅实现对单个客户

    2024年02月03日
    浏览(30)
  • 【Linux网络】网络编程套接字 -- 基于socket实现一个简单UDP网络程序

    我们把数据从A主机发送到B主机,是目的吗?不是,真正通信的不是这两个机器!其实是这两台机器上面的软件(人) 数据有 IP(公网) 标识一台唯一的主机 ,用谁来标识各自主机上客户或者服务进程的唯一性呢? 为了更好的表示一台主机上服务进程的唯一性,我们采用 端口号

    2024年02月12日
    浏览(39)
  • Linux网络编程:socket & fork实现clients/server通信

    UNIX网络编程:socket实现client/server通信 随笔简单介绍了TCP Server服务单客户端的socket通信,但是并未涉及多客户端通信。 对于网络编程肯定涉及到多客户端通信和并发编程 (指在同时有大量的客户链接到同一服务器),故本随笔补充这部分知识。 而且并发并发编程涉及到多进程

    2024年02月05日
    浏览(37)
  • 【网络编程】TCP Socket编程

    流套接字: 使用传输层TCP协议 TCP: 即Transmission Control Protocol(传输控制协议),传输层协议。 TCP的特点: 有连接 可靠传输 面向字节流 有接收缓冲区,也有发送缓冲区 大小不限 ServerSocket 是 创建TCP服务端Socket 的API。 注意: ServerSocket 只能用于 服务器端。 构造方法: 方法签名

    2024年02月07日
    浏览(40)
  • Linux学习之网络编程2(socket,简单C/S模型)

    Linux网络编程我是看视频学的,Linux网络编程,看完这个视频大概网络编程的基础差不多就掌握了。这个系列是我看这个Linux网络编程视频写的笔记总结。 小端法:pc本地存储,高位存高地址,低位存低地址。 大端法:网络存储,高位存低地址,低位存高地址。 由此我们看到

    2024年02月01日
    浏览(39)
  • Linux网络编程:Socket套接字编程(Server服务器 Client客户端)

    文章目录: 一:定义和流程分析 1.定义 2.流程分析  3.网络字节序 二:相关函数  IP地址转换函数inet_pton inet_ntop(本地字节序 网络字节序) socket函数(创建一个套接字) bind函数(给socket绑定一个服务器地址结构(IP+port)) listen函数(设置最大连接数或者说能同时进行三次握手的最

    2024年02月12日
    浏览(67)
  • 【探索Linux】—— 强大的命令行工具 P.26(网络编程套接字基本概念—— socket编程接口 | socket编程接口相关函数详细介绍 )

    本文将深入探讨使用套接字进行网络通信的基本步骤,包括创建套接字、绑定地址、监听连接(对于服务器端)、连接远程主机(对于客户端)、以及发送和接收数据等操作。套接字编程涉及一系列系统调用和函数,如 socket() 、 bind() 、 listen() 、 connect() 、 send() 、 recv() 等。

    2024年03月10日
    浏览(63)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包