操作系统socket通信实验

操作系统socket通信实验


一、实验内容

分别编一个客户机程序和服务器程序,首先建立客户程序与服务器之间正确的socket连结,然后利用send和recv函数,客户程序将一个较长的文本文件(如几k字节)中的数据发送给服务器。要求服务器全部正确地接收到所有的数据(一个也不能少),并将其存入一个文件。

二、程序实现
1. 实验程序框图

在这里插入图片描述

如上图所示,服务器端建立套接字后绑定本地ip地址和端口,等待客户端连接。客户端建立套接字后与服务器端建立连接。客户端从发送文件不断读出内容,从缓冲去发送到套接字,直到发送完所有内容。服务器端从套接字中接收内容,不断写入接收文件,直到没有内容。收发过程结束后,关闭打开文件,关闭套接字,断开socket连接。

2. 实验数据结构说明

以下是本次实验中主要用到的常量和数据结构的说明。

#define AF_INET 2   //用于网络连接的通信域,支持UDP,TCP
#define SOCK_SYREAM 1   //通过虚电路方式通信
#define BUFSIZE 1024    //缓冲区大小
#define PORT 8888   //服务器端口号为8888

struct sockaddr_in  //互联网域地址
{
    short sin_family;   //通信域值为AF_INET
    u_short sin_port;   //16位端口号
    struct in_addr sin_addr;    //32位IP地址
}

struct in_addr
{
    u_long s_addr;   //32位IP地址
}
3. 实验环境说明

本实验的客户机和服务器分别位于两台Ubuntu 22.04虚拟机上,并且二者处于同一子网192.168.66.0中。其中,服务器端的ip地址为192.168.66.128,服务器端用来建立socket连接的端口号为8888。客户端的ip地址为192.168.66.129。
在这里插入图片描述

在这里插入图片描述

4. 服务器端程序
#include <sys/socket.h>
#include <stdio.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <arpa/inet.h>

#define BUFSIZE 1024
#define PORT 8888

void main()
{
    int sockfd,newsockfd,length,count;
    char buf[BUFSIZE];
    FILE *recever = fopen("./recever.txt","w");
    sockfd = socket(AF_INET, SOCK_STREAM, 0); //生成套结字
    struct sockaddr_in server_addr;//服务器地址
    server_addr.sin_family = AF_INET;
    //服务器IP地址,并将其转换为in_addr格式
    server_addr.sin_addr.s_addr = inet_addr("192.168.66.128");
    server_addr.sin_port = htons(PORT);//指定服务器8888端口
    if(bind(sockfd,(struct sockaddr *)&server_addr,sizeof(server_addr))==0)
        printf("socket created at port%d\n", ntohs(server_addr.sin_port));
    else printf("error\n");
    listen(sockfd,2);//允许最多两个连接
    while(1)
    {
        printf("waiting....\n");
        newsockfd = accept(sockfd,(struct sockaddr *)0,(int *)0);
        printf("connect with a client\n");
        if(!fork())//创建子进程
        {
            close(sockfd);
            while ((count = recv(newsockfd,buf,sizeof(buf),0))>0)//接收消息
            {
                fwrite(buf,sizeof(char),count,recever);//写入文件
                bzero(buf,sizeof(buf));//清空缓存
            }
            printf("receive finished!\n");
            exit(0);
        }
        fclose(recever);
        close(newsockfd);
    }
}
5. 客户端程序
#include <sys/socket.h>
#include <stdio.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>

#define BUFSIZE 1024
#define PORT 8888

void main()
{
    int sockfd,count;
    struct  sockaddr_in server;
    char buf[BUFSIZE];
    FILE *sendfile = fopen("./send.txt","r");//打开发送文件
    sockfd = socket(AF_INET,SOCK_STREAM,0);//创建套接字
    if(sockfd<0)
    {
        printf("create fail\n");
        return;
    }       
    server.sin_family = AF_INET;
    //将服务器ip地址转换为in_addr格式
    server.sin_addr.s_addr = inet_addr("192.168.66.128");
    server.sin_port=htons(PORT);
    //建立socket连接
    if(connect(sockfd,(struct sockaddr *)&server,sizeof(server))<0)
    {
        printf("connect fail\n");
        return;
    }     
    //读入发送内容到缓冲区,每次最多读1024字节
    while((count=fread(buf,sizeof(char),BUFSIZE,sendfile))>0)
    {
        if((count=send(sockfd,buf,count,0))>0)//发送内容到套接字
            printf("%dByte send\n",count);
        bzero(buf,BUFSIZE);//清空发送缓冲区
    }
    close(sockfd);//关闭套接字
}
三、功能测试
1. 纯文本文件发送

为了测试的准确性,随机生成含有11.3KB的文本文件send.txt作为发送文件。
在这里插入图片描述

先启动服务器程序,再启动客户端程序,使用的命令如下图所示。


将接收得到的文件与原始的发送文件做对比,准确无误的接收到了所有的数据。

在这里插入图片描述

2. 二进制文件发送

为了进一步测试发送的准确性,编写了一个C语言HelloWorld程序,并将其编译成可执行的二进制文件作为发送文件,大小为16kB。
在这里插入图片描述

先启动服务器程序,再启动客户端程序。得到了接收到的Receiver文件。先更改文件权限,再运行程序,发现二进制文件的功能是一致的。
在这里插入图片描述

为了进一步确定接收到二进制文件是否与原文件有差异,将hello文件拷贝到服务器所在虚拟机,然后使用cmp命令比较二者是否相同。cmp函数没有报错,说明接收到的Receiver文件的确与原文件相同。
在这里插入图片描述

四、总结与感悟

通过本次实验,让我更加理解了两个远程的进程之间的通信是如何通过socket来完成的,两端进程建立套接字后以服务器/客户端模式进行连接,通过向套接字写入和读出,实现了两个远程进程之间的通信。也由此掌握了数据在电脑主机上的存储方式是小端序,而在网络流中是大端序,故而要对IP地址和端口进行转换。
不可避免的,我在实验过程中也犯了一个错,发现接收到的文本文件最后总是会有一些乱码。起初我以为是发送端在文件读完后还发送了其他内容,仔细检查逻辑后发现没有问题,后来我用二进制查看器打开后发现多出来的是\00\00\00\00也就是四个空字节,所以就定位到服务器端的接收上,将每次向文件写入1024字节改为,每次写入接收到的字节数count个,从而成功解决了问题。
在这里插入图片描述

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值