思维导图
练习题
广播服务器端
#include <myhead.h>int main(int argc, char const *argv[])
{//创建套接字int sfd = socket(AF_INET, SOCK_DGRAM, 0);//填充网络信息结构体struct sockaddr_in cin;cin.sin_family = AF_INET;cin.sin_port = htons(6789);cin.sin_addr.s_addr = inet_addr("192.168.124.255");//绑定bind(sfd, (struct sockaddr *)&cin, sizeof(cin));char buf[128] = "";//接收广播消息while (1){memset(buf, 0, sizeof(buf));recvfrom(sfd, buf, sizeof(buf), 0, NULL, NULL);printf("接收到的消息:%s\n",buf);}//关闭套接字close(sfd);return 0;
}
广播客户端
#include <myhead.h>int main(int argc, char const *argv[])
{//创建套接字int sfd = socket(AF_INET, SOCK_DGRAM, 0);//将套接字设置成允许广播int broadcase = 1;if (setsockopt(sfd, SOL_SOCKET, SO_BROADCAST, &broadcase, sizeof(broadcase)) == -1){perror("setsockopt error");return -1;}//填充网络信息结构体struct sockaddr_in cin;cin.sin_family = AF_INET;cin.sin_port = htons(6789);cin.sin_addr.s_addr = inet_addr("192.168.124.255");//绑定非必要//bind(sfd, (struct sockaddr *)&cin, sizeof(cin));char buf[128] = "";//发送广播消息while (1){memset(buf, 0, sizeof(buf));printf("请输入--->");fgets(buf,sizeof(buf),stdin);buf[strlen(buf)-1]='\0';//发送到广播地址中去sendto(sfd, buf, sizeof(buf), 0, (struct sockaddr*)&cin, sizeof(cin));printf("发送成功\n");}close(sfd);return 0;
}
组播服务器端
#include <myhead.h>int main(int argc, char const *argv[])
{//创建套接字int rfd = socket(AF_INET, SOCK_DGRAM, 0);if (rfd == -1){perror("socket error");return -1;}//设置网络属性struct ip_mreqn im;im.imr_multiaddr.s_addr = inet_addr("224.1.2.3");im.imr_address.s_addr = inet_addr("192.168.125.193");im.imr_ifindex = 2;if (setsockopt(rfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &im, sizeof(im)) == -1){perror("setsockopt error");return -1;}puts("加入多播组成功");//填充地址信息结构体struct sockaddr_in rin;rin.sin_family = AF_INET;rin.sin_port = htons(9999);rin.sin_addr.s_addr = inet_addr("224.1.2.3");//绑定if (bind(rfd, (struct sockaddr *)&rin, sizeof(rin)) == -1){perror("绑定成功");return -1;}puts("绑定成功");//接收消息char buf[128]="";while(1){memset(buf,0,sizeof(buf));recvfrom(rfd,buf,sizeof(buf),0,0,0);printf("收到消息为:%s\n",buf);}//关闭套接字close(rfd);return 0;
}
组播客户端
#include <myhead.h>int main(int argc, char const *argv[])
{//创建套接字int sfd = socket(AF_INET, SOCK_DGRAM, 0);if (sfd == -1){perror("socket error");return -1;}//发送端不用设置网络属性//填充地址信息结构体struct sockaddr_in sin;sin.sin_family = AF_INET;sin.sin_port = htons(9999);sin.sin_addr.s_addr = inet_addr("224.1.2.3");//绑定非必要/*if (bind(sfd, (struct sockaddr *)&sin, sizeof(sin)) == -1){perror("绑定成功");return -1;}puts("绑定成功");*///发送消息char buf[128] = "";while (1){memset(buf, 0, sizeof(buf));fgets(buf, sizeof(buf), stdin);buf[strlen(buf) - 1] = 0;//发送给指定IP端口sendto(sfd, buf, sizeof(buf), 0, (struct sockaddr*)&sin, sizeof(sin));printf("收到消息为:%s\n", buf);}//关闭套接字close(sfd);return 0;
}
流式域套接字
服务器端
#include <myhead.h>int main(int argc, const char *argv[])
{//1、创建套接字int sfd = socket(AF_UNIX, SOCK_STREAM, 0);//int sfd = socket(AF_UNIX, SOCK_RAW, IPPROTO_TCP);if (sfd == -1){perror("socket error");return -1;}//由于域套接字的绑定函数,只能绑定一个不存在的套接字文件//所以,在绑定之前需要判断当前文件是否存在if (access("./unix", F_OK) == 0){//表示文件存在,删除该文件if (unlink("./unix") == -1){perror("unlink error");return -1;}}//2、填充地址信息结构体struct sockaddr_un sun;sun.sun_family = AF_UNIX; //通信域//sun.sun_path = ".unix"; //字符串赋值不能使用赋值运算符strcpy(sun.sun_path, "./unix"); //绑定套接字文件//3、绑定地址信息结构体if (bind(sfd, (struct sockaddr *)&sun, sizeof(sun)) == -1){perror("bind error");return -1;}printf("bind success\n");//4、监听if (listen(sfd, 128) == -1){perror("listen error");return -1;}//5、阻塞接收客户端链接请求//定义容器接收客户端地址信息结构体struct sockaddr_un cun;socklen_t socklen = sizeof(cun);int newfd = accept(sfd, (struct sockaddr *)&cun, &socklen); //表示不接收客户端地址信息if (newfd == -1){perror("accept error");return -1;}//6、收发数据char buf[128] = "";while (1){//清空数组bzero(buf, sizeof(buf));int res = recv(newfd, buf, sizeof(buf), 0); //读取消息if (res == 0){printf("客户端已经下线\n");break;}printf("[%s]: %s\n", cun.sun_path, buf);}//7、关闭套接字close(newfd);close(sfd);return 0;
}
客户端
#include <myhead.h>int main(int argc, char const *argv[])
{//创建套接字int cfd = socket(AF_UNIX, SOCK_STREAM, 0);if (cfd == -1){perror("socket error");return -1;}//判断Linux文件是否存在if (access("./linux", F_OK) == 0){if (unlink("./linux") == -1){perror("unlink error");return -1;}}//填充信息结构体struct sockaddr_un cun;cun.sun_family = AF_UNIX;strcpy(cun.sun_path, "./linux");//绑定信息结构体if (bind(cfd, (struct sockaddr *)&cun, sizeof(cun)) == -1){perror("bind error");return -1;}puts("bind success");//连接服务器//填充服务器地址信息结构体struct sockaddr_un sun;sun.sun_family = AF_UNIX;strcpy(sun.sun_path, "./unix");//连接服务器connect(cfd, (struct sockaddr *)&sun, sizeof(sun));//收发数据char buf[128] = "";while (1){//清空数组memset(buf, 0, sizeof(buf));//获取消息内容fgets(buf, sizeof(buf), stdin);buf[strlen(buf) - 1] = 0;//发送消息send(cfd, buf, sizeof(buf), 0);printf("发送成功\n");if (strcmp(buf, "quit") == 0){break;}}//关闭套接字close(cfd);return 0;
}
报式域套接字
服务器端
#include<myhead.h>int main(int argc, const char *argv[])
{//创建套接字int sfd = socket(AF_UNIX, SOCK_DGRAM, 0);if(sfd == -1){perror("socket error");return -1;}printf("sfd = %d\n", sfd);//由于域套接字的绑定函数,只能绑定一个不存在的套接字文件//所以,在绑定之前需要判断当前文件是否存在if(access("./linux", F_OK) == 0){ //表示文件存在,删除该文件if(unlink("./linux")==-1){perror("unlink error");return -1; }} // 填充地址信息结构体struct sockaddr_un sun;sun.sun_family = AF_UNIX;strcpy(sun.sun_path, "./linux");// 绑定工作if(bind(sfd, (struct sockaddr*)&sun, sizeof(sun)) == -1){perror("bind error");return -1;}//数据收发char buf[128] = "";//定义变量存放客户端地址信息结构体struct sockaddr_un cun;socklen_t socklen = sizeof(cun);while(1){//清空数组bzero(buf, sizeof(buf));//从套接字文件中读取消息recvfrom(sfd, buf, sizeof(buf), 0, (struct sockaddr*)&cun, &socklen);printf("[%s]:%s\n", cun.sun_path, buf);//将字符串连接后回发strcat(buf, "*.*");//if(write(sfd, buf, sizeof(buf)) == -1)if(sendto(sfd, buf, sizeof(buf), 0, (struct sockaddr*)&cun, sizeof(cun)) == -1){perror("sendto error");return -1;}printf("发送成功\n");}//4、关闭套接字close(sfd);return 0;
}
客户端
#include <myhead.h>int main(int argc, const char *argv[])
{//1、创建用于通信的套接字文件描述符int cfd = socket(AF_UNIX, SOCK_DGRAM, 0);if (cfd == -1){perror("socket error");return -1;}//由于域套接字的绑定函数,只能绑定一个不存在的套接字文件//所以,在绑定之前需要判断当前文件是否存在if (access("./unix", F_OK) == 0){//表示文件存在,删除该文件if (unlink("./unix") == -1){perror("unlink error");return -1;}}//2、绑定//2.1 填充地址信息结构体struct sockaddr_un cun;cun.sun_family = AF_UNIX;strcpy(cun.sun_path, "./unix");//2.2 绑定工作if (bind(cfd, (struct sockaddr *)&cun, sizeof(cun)) == -1){perror("bind error");return -1;}//3、填充服务器的地址信息结构体struct sockaddr_un sun;sun.sun_family = AF_UNIX;strcpy(sun.sun_path, "./linux");//4、数据收发char buf[128] = "";while (1){printf("请输入>>>");fgets(buf, sizeof(buf), stdin);buf[strlen(buf) - 1] = '\0';//发送给服务器sendto(cfd, buf, sizeof(buf), 0, (struct sockaddr *)&sun, sizeof(sun));if (strcmp(buf, "quit") == 0){break;}//接收服务器发送来的消息recvfrom(cfd, buf, sizeof(buf), 0, NULL, NULL);printf("收到消息:%s\n", buf);}//5、关闭套接字close(cfd);return 0;
}
使用TFTP协议完成客户端的文件上传下载功能
#include <myhead.h>
int fileonload(int sockfd)
{int sfd = sockfd;printf("上传的文件:");char file[64];scanf("%s", file);//打开文件用于读取上传文件的数据int send_fd = -1;if ((send_fd = open(file, O_RDONLY)) == -1){perror("open error:");return -1;}//填充信息结构体struct sockaddr_in sin;sin.sin_family = AF_INET;sin.sin_port = htons(69);sin.sin_addr.s_addr = inet_addr("192.168.125.60");socklen_t socklen = sizeof(sin);//封装请求下载数据包//第一块
}
int main(int argc, char const *argv[])
{// 创建套接字UDP通信int sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (-1 == sockfd){perror("socket error");return -1;}// 填充服务器网络信息结构体struct sockaddr_in sin;sin.sin_family = AF_INET;//端口号填69sin.sin_port = htons(69);//填写windows ip地址sin.sin_addr.s_addr = inet_addr("192.168.125.60");//结构体长度socklen_t socklen = sizeof(sin);//数据包数据的长度以512字节传输char buffer[516] = {0};//返回的ACKchar ack[4];//操作码short code = 0;//块编号 or 错误码short BlockoErr = 0;//数据的长度以512Byte传输char text[512] = {0}; //文件内容 或 错误信息//校验收到的块编号int N = 0;//返回的文件描述符int fd;int ret = 0;//文件名char filename[64] = {0};while (1){int chose = 0;puts("1.下载");puts("2.上传");puts("3.退出");scanf("%d", &chose);switch (chose){case 1:memset(filename, 0, sizeof(filename));//输入文件名printf("下载文件名: ");scanf("%s", filename);//使用 sprintf 组包//返回成功格式化字符的个数 01下载操作 10上传操作ret = sprintf(buffer, "%c%c%s%c%s%c", 0, 1, filename, 0, "octet", 0);//首次发送请求if (-1 == sendto(sockfd, buffer, ret, 0, (struct sockaddr *)&sin, socklen)){perror("sendto error");return -1;}//循环接收服务器发来的数据包while (1){//因为有临时端口需要保存服务器的网络信息结构体ret = recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr *)&sin, &socklen);if (-1 == ret){perror("recvfrom error");return -1;}//解析操作码code = ntohs(*(short *)buffer);//解析块编号or错误码BlockoErr = ntohs(*(short *)(buffer + 2));//解析文件内容or错误信息,并将内容放入数据段strncpy(text, buffer + 4, sizeof(text));//解析数据包中的内容if (3 == code && BlockoErr == N + 1){//校验块编号+1N++;//要接收的数据包//如果是第一次接到数据包 要创建文件if (BlockoErr == 1){fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0664);if (-1 == fd){perror("open error");}}//将文件内容写入文件 留出4字节if (-1 == write(fd, text, ret - 4)){perror("write error");}// 组装ACK*(short *)ack = htons(4);*(short *)(ack + 2) = htons(BlockoErr);//回复ACK包if (-1 == sendto(sockfd, ack, 4, 0, (struct sockaddr *)&sin, socklen)){perror("recvfrom error");}//文件接收完毕if (ret < 512)break;}}printf("文件[%s]下载完成\n", filename);close(sockfd);break;case 2:memset(filename, 0, sizeof(filename));//输入文件名printf("上传文件名: ");scanf("%s", filename);int upfd = -1;if ((upfd = open(filename, O_RDONLY)) == -1){perror("open error:");return -1;}short *p1 = (short *)buffer;*p1 = htons(2);//第二模块char *p2 = buffer + 2;strcpy(p2, filename);//第三模块char *p3 = p2 + strlen(p2) + 1;strcpy(p3, "octet");int len = 4 + strlen(p2) + strlen(p3);sendto(sockfd, buffer, len, 0, (struct sockaddr *)&sin, sizeof(sin));char *data_point = buffer + 4;short *cmd_point = (short *)buffer;*cmd_point = htons(3);short *block_point = (short *)(buffer + 2);*block_point = htons(1);int i = 1;while (1){recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr *)&sin, &socklen);if (*cmd_point == htons(4)){int res = read(upfd, buffer + 4, 512);if (res == 0){break;}*cmd_point = htons(3);sendto(sockfd, buffer, res + 4, 0, (struct sockaddr *)&sin, socklen);}}printf("文件[%s]上传完成\n", filename);close(sockfd);break;case 3:exit(0);default:puts("error");}}return 0;
}