Socket编程 ——UDP 实验报告

来源:互联网 发布:crossgear 知乎 编辑:程序博客网 时间:2024/06/03 22:55

一 客户端数据反射交互

(1)实验内容

要求:利用数据报套接字实现数据传输

  • 客户端创建UDP套接字,向指定的服务端发送数据;
  • 服务端接收到新数据,显示是谁发送过来的,并把该数据回传给发送方;
  • 服务端使用多线程来实现并发

(2)实现方法

Client

unsigned int port;    char recvData[255];     cin >> sendData;    sendto(sclient,sendData, 255, 0, (sockaddr *)&sin, len);      // 向服务器端发送数据
int ret = recvfrom(sclient, (char *)&port, 4, 0, (sockaddr *)&sin, &len);      sin.sin_port=htons(port);     ret = recvfrom(sclient, recvData,255, 0, (sockaddr *)&sin, &len);      if(ret > 0)     cout<<recvData<<endl;    //接受改变的端口值 并接受反回的信息
while(1)    {cout<<"Input your message:";cin >> sendData;    sendto(sclient,sendData, sizeof(sendData), 0, (sockaddr *)&sin, len);int ret = recvfrom(sclient, recvData,255, 0, (sockaddr *)&sin, &len);  if(ret > 0)             cout<<"From server:"<<recvData<<endl;   cin>>s;        if (s!=s1)//是否关闭套接字            break;    }    //做到与服务器交互

server

  while (true)     {     char recvData[255]; char sendData[255];     int ret = recvfrom(serSocket, recvData, 255, 0, (sockaddr *)&remoteAddr, &nAddrLen); NUM++;if (ret > 0)        cout<<"Connect a new user ,total Nummber is "<<NUM<<endl;//如果有新的用户加入8080端口则用户数量加一 mystruct.client = remoteAddr;mystruct.userid = NUM;memcpy(mystruct.recvData,recvData,255);hThread = CreateThread(NULL, 0, ClientThread, (LPVOID)&mystruct, 0, NULL);//创建新的线程 在线程里生成新的临时端口与用户进行交互 }
子线程代码DWORD WINAPI ClientThread(LPVOID lpParameter){    SOCKET ChildSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);   //建立新线程······}
int PORT=1024;while ( PORT <= 65535){        serAddr.sin_family = AF_INET;        serAddr.sin_port = htons( PORT);        serAddr.sin_addr.S_un.S_addr = INADDR_ANY;        if (bind(ChildSocket, (sockaddr *)&serAddr, sizeof(serAddr)) == SOCKET_ERROR)            PORT++;        else            break;    }    //寻找并绑定可用的端口
my_struct  mystruct = (my_struct) lpParameter;//接收主进程的客户端参数client = mystruct ->client;userid = mystruct->userid;//用户识别号 nAddrLen = mystruct->nAddrLen;sendto(ChildSocket,(const char *)&PORT,4, 0, (sockaddr *)&client, nAddrLen);         //将端口号发至客户端进行更改sendto(ChildSocket, mystruct->recvData, 255, 0, (sockaddr *)&client, nAddrLen);    //第一次信息反弹至客户端
while(1){     int ret = recvfrom(ChildSocket,mystruct-> recvData, 255, 0, (sockaddr *)& client,& nAddrLen);       if (ret > 0)        cout<<"FROM user"<<userid<<":"<<mystruct->recvData<<endl; //ntohs(serAddr.sin_port)     sendto(ChildSocket, mystruct->recvData, 255, 0, (sockaddr *)& client, nAddrLen);}//后续的信息反弹

(3)实验实现

服务器端
多个客户端同时连接 ,实现用户识别及交叉发送数据
这里写图片描述

用户1
这里写图片描述

用户2
这里写图片描述

二 使用UDP套接字实现文件传输

(1)实验内容

  • 客户端向服务端发送文件名
  • 客户端向服务端传输文件内容
  • 双方关闭套接字

(2)实验方法

Client

    unsigned int port=0;    char recvData[255];     cout<<"Input your filename:";    cin >> name;    sendto(sclient,name, 20, 0, (sockaddr *)&sin, len);      // 向服务器端发送文件名
int ret = recvfrom(sclient, (char *)&port, 4, 0, (sockaddr *)&sin, &len);      sin.sin_port=htons(port);    //接受改变的端口值 并接受反回的信息
fp = fopen(name,"rb");        if(fp==NULL) {cout<<"no suchfile again input:"; }        fseek(fp,0L,SEEK_END);        file_size = ftell( fp );        fseek(fp,0L,SEEK_SET);        sendto(sclient,(const char *)&file_size, 4, 0, (sockaddr *)&sin, len);        //文件的建立 长度并发送
while(file_size){if(file_size>=1024){fread(data,1,1024,fp);sendto(sclient, data, 1024, 0, (sockaddr *)&sin, len);file_size -= 1024;}else {fread(data,1,file_size,fp); sendto(sclient, data, file_size, 0, (sockaddr *)&sin, len);file_size = 0;}}    // 读取文件并传送

Server

int NUM=0; //计算当前用户的数量typedef struct MyStruct{      sockaddr_in client;      int nAddrLen;      char recvData[255];      int userid;             char name[20];}MyStruct, *my_struct ;//定义结构体 在创线程的时候使用
 while (true)     {        char recvData[255];         char sendData[255];        memset(recvData,0,255);        recvfrom(serSocket,recvData, 20, 0, (sockaddr *)& remoteAddr,& nAddrLen);          NUM++;        cout<<"Connect a new user ,total Nummber is "<<NUM<<endl;        //如果有新的用户加入8080端口则用户数量加一         mystruct.userid = NUM;        mystruct.client = remoteAddr;        memcpy(mystruct.name,recvData,20);        hThread = CreateThread(NULL, 0, ClientThread, (LPVOID)&mystruct, 0, NULL);        //创建新的线程 在线程里生成新的临时端口与用户进行交互    }

创建新线程

SOCKET ChildSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);   //新的套接字while ( PORT <= 65535){    serAddr.sin_family = AF_INET;    serAddr.sin_port = htons( PORT);    serAddr.sin_addr.S_un.S_addr = INADDR_ANY;    if (bind(ChildSocket, (sockaddr *)&serAddr, sizeof(serAddr)) == SOCKET_ERROR)        PORT++;    else        break;        }    //寻找可用的端口
    my_struct  mystruct = (my_struct) lpParameter;    client = mystruct ->client;    userid = mystruct->userid;    nAddrLen = mystruct->nAddrLen;    sendto(ChildSocket,(const char *)&PORT,4, 0, (sockaddr *)&client, nAddrLen);         //将端口号发至客户端进行更改
//新建文件char a[4];unsigned int len=0;recvfrom(ChildSocket,(char *)&len, 4, 0, (sockaddr *)& client,& nAddrLen);  FILE *dest_fp; dest_fp = fopen(mystruct->name, "ab");while(1){while(len){    if(len>=1024) {recvfrom(ChildSocket,data, 1024, 0, (sockaddr *)& client,& nAddrLen) ;fwrite(data,1, 1024, dest_fp);fflush(dest_fp);len = len - 1024;}    else {recvfrom(ChildSocket,data, len, 0, (sockaddr *)& client,& nAddrLen) ;fwrite(data,1,len,dest_fp);fflush(dest_fp);len  = 0;}}     fclose(dest_fp);}//文件建立与写入

(3)实验实现

服务器每次用户连接创建新的线程
这里写图片描述

用户一
这里写图片描述
用户二
这里写图片描述

文件夹
这里写图片描述

这里写图片描述

0 0