作业1
题目
将UDP服务器客户端脱离笔记重新搭建
结果
代码
server.c
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/udp.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#define IP "172.27.56.253"
#define PORT 6666
#define ERR_MSG(msg) \
do { \
fprintf(stderr, "error in __%d__\n", __LINE__); \
perror(msg); \
} while (0);
int main(int argc, char const *argv[])
{
int sfd; // 套接字文件
struct sockaddr_in addr_server; // 服务器IP端口
struct sockaddr_in addr_recvbuf; // 地址缓存
socklen_t addr_recvbuf_len; // 地址缓存长度
char buf[1024];
// 开启报式套接字
sfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sfd < 0) {
ERR_MSG("socket()");
return -1;
}
// 绑定sfd
addr_server.sin_family = AF_INET;
addr_server.sin_addr.s_addr = inet_addr(IP);
addr_server.sin_port = htons(PORT);
if(bind(sfd, (struct sockaddr *)&addr_server, sizeof(addr_server))<0){
ERR_MSG("binf()");
return -1;
};
while (1) {
// 接收
memset(buf,0,sizeof(buf));
recvfrom(sfd, buf, sizeof(buf), 0, (struct sockaddr *)&addr_recvbuf, &addr_recvbuf_len);
printf("[%s:%d] : %s\n",inet_ntoa(addr_recvbuf.sin_addr),ntohs(addr_recvbuf.sin_port),buf);
// 发送
strcat(buf, "######");
sendto(sfd, buf, sizeof(buf), 0, (struct sockaddr *)&addr_recvbuf, sizeof(addr_recvbuf));
}
// 关闭
close(sfd);
return 0;
}
client.c
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/udp.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#define IP "172.27.56.253"
#define PORT 6666
#define ERR_MSG(msg) \
do { \
fprintf(stderr, "error in __%d__\n", __LINE__); \
perror(msg); \
} while (0);
int main(int argc, char const *argv[])
{
int cfd; // 套接字文件
struct sockaddr_in addr_server; // 服务器IP端口
struct sockaddr_in addr_recvbuf; // 地址缓存
socklen_t addr_recvbuf_len; // 地址缓存长度
char buf[1024];
// 开启报式套接字
cfd = socket(AF_INET, SOCK_DGRAM, 0);
if (cfd < 0) {
ERR_MSG("socket()");
return -1;
}
// 设置要连接的服务器
addr_server.sin_family = AF_INET;
addr_server.sin_addr.s_addr = inet_addr(IP);
addr_server.sin_port = htons(PORT);
while (1) {
// 发送
fgets(buf,sizeof(buf),stdin);
buf[strlen(buf)-1] = '\0';
sendto(cfd, buf, sizeof(buf), 0, (struct sockaddr *)&addr_server, sizeof(addr_server));
// 接收
memset(buf,0,sizeof(buf));
recvfrom(cfd, buf, sizeof(buf), 0, (struct sockaddr *)&addr_recvbuf, &addr_recvbuf_len);
printf("[%s:%d] : %s\n",inet_ntoa(addr_recvbuf.sin_addr),ntohs(addr_recvbuf.sin_port),buf);
}
// 关闭
close(cfd);
return 0;
}
作业2
题目
完成tftp
下载上传
结果
代码
main.c
#include "tftp.h"
int main(int argc, const char *argv[])
{
int cfd; // sockfd
struct sockaddr_in addr_server; // 服务器:协议地址端口
char ch; // 选项
// 创建套接字
cfd = socket(AF_INET, SOCK_DGRAM, 0);
if (cfd < 0) {
ERR_MSG("socket");
return -1;
}
addr_server.sin_family = AF_INET; // 必须填充AF_INET
addr_server.sin_port = htons(SER_PORT); // 1024~49151
addr_server.sin_addr.s_addr = inet_addr(SER_IP); // tftp服务器所在的ip
// 上传or下载文件
while (1) {
printf("================== d = download ================\n");
printf("================== u = upload ================\n");
printf("================== q = quit ================\n");
printf("please select : ");
ch = getchar();
while (getchar() != '\n')
;
if (ch == 'd' || ch == 'D') {
download_file(cfd, addr_server); // 下载文件
} else if (ch == 'u' || ch == 'U') {
upload_file(cfd, addr_server); // 上传文件
} else if (ch == 'q' || ch == 'Q') {
break;
} else {
printf("illegal input\n");
continue;
}
}
// 关闭套接字
close(cfd);
return 0;
}
tftp.c
#include "tftp.h"
// 设置文件名
char *set_name(char *buf, int size)
{
printf("please input the filename: ");
fgets(buf, size, stdin);
buf[strlen(buf) - 1] = '\0';
return buf;
}
// 发送读、写请求
void send_rdwe_request(int cfd, struct sockaddr_in addr_server, char *filename, char ope_code)
{
// 发送下载请求
char buf[516] = "";
bzero(buf, sizeof(buf));
int size = sprintf(buf, "%c%c%s%c%s%c", 0x00, ope_code, filename, 0, "octet", 0);
// sendto将数据发送给服务器,所需要填充服务器的地址信息结构体
if (sendto(cfd, buf, size, 0, (struct sockaddr *)&addr_server, sizeof(addr_server)) < 0) {
ERR_MSG("sendto");
exit(-1);
}
printf("request has sended successfully\n");
}
// 处理错误码
void handle_errno(char *buf, ssize_t len)
{
char *start = buf + 4;
char *end = buf + len - 1;
*end = '\0';
printf("error occurred: %s\n", start);
}
// 下载文件
void download_file(int cfd, struct sockaddr_in addr_server)
{
char filename[NAME_SIZE] = "";
FILE *fp = 0;
char buf[4 + DATA_SIZE] = "";
struct sockaddr_in addr_recvbuf; // 服务器地址缓存
socklen_t addr_recvbuf_len; // 服务器地址缓存长度
ssize_t len; // 接收字节数
// 设置文件名
set_name(filename, sizeof(filename));
// 发送下载请求
send_rdwe_request(cfd, addr_server, filename, RD);
fp = fopen(filename, "a");
while (1) {
memset(buf, 0, sizeof(buf));
// 接收数据包
len = recvfrom(cfd, buf, sizeof(buf), 0, (struct sockaddr *)&addr_recvbuf, &addr_recvbuf_len);
if (len < 0) {
ERR_MSG("recvfrom()");
break;
}
// buf写入fp
if (OPE_CODE == DATA) {
for (int i = 4; i < len; i++) {
fputc(buf[i], fp);
}
// 发送ack
OPE_CODE = ACK;
sendto(cfd, buf, 4, 0, (struct sockaddr *)&addr_recvbuf, sizeof(addr_recvbuf));
}
// error
if (OPE_CODE == ERR) { // 操作码 = 5
handle_errno(buf, len);
break;
}
// 退出
if (len < DATA_SIZE + 4)
break;
}
printf("file download successfully\n");
fclose(fp);
}
// 上传文件
void upload_file(int cfd, struct sockaddr_in addr_server)
{
char filename[NAME_SIZE] = "";
struct sockaddr_in addr_recvbuf; // 服务器地址缓存
socklen_t addr_recvbuf_len; // 服务器地址缓存长度
int len = 0; // 包节数数
FILE *fp;
char buf[DATA_SIZE + 4] = "";
int cnt = 0; // 数据块编号
// 设置文件名
set_name(filename, sizeof(filename));
// 发送上传请求
send_rdwe_request(cfd, addr_server, filename, WR);
fp = fopen(filename, "r");
memset(buf, 0, sizeof(buf));
while (1) {
// 接收ack
recvfrom(cfd, buf, sizeof(buf), 0, (struct sockaddr *)&addr_recvbuf, &addr_recvbuf_len);
// 错误
if (OPE_CODE == ERR) {
handle_errno(buf, sizeof(buf));
break;
}
// 发送数据包
OPE_CODE = DATA;
BLOCK_NO++;
for (int i = 4; i < DATA_SIZE + 4; i++) {
buf[i] = fgetc(fp);
if (buf[i] == EOF) {
buf[i] = '\0';
break;
}
len++;
}
sendto(cfd, buf, sizeof(buf), 0, (struct sockaddr *)&addr_recvbuf, addr_recvbuf_len);
// 退出条件
if (len < DATA_SIZE)
break;
}
printf("file upload successfully\n");
fclose(fp);
}
tftp.h
#ifndef _TFTP_H_
#define _TFTP_H_
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
// operate code
#define RD 1
#define WR 2
#define DATA 3
#define ACK 4
#define ERR 5
#define DATA_SIZE 512
#define NAME_SIZE 32
#define OPE_CODE buf[1]
#define BLOCK_NO buf[3]
// udp server
#define SER_IP "192.168.31.6"
#define SER_PORT 69
// err msg
#define ERR_MSG(msg) \
do { \
fprintf(stderr, "line:%d", __LINE__); \
perror(msg); \
} while (0)
// functions
char *set_name(char *buf, int size);
void send_rdwe_request(int cfd, struct sockaddr_in addr_server, char *filename, char ope_code);
void handle_errno(char *buf, ssize_t len);
void download_file(int cfd, struct sockaddr_in addr_server);
void upload_file(int cfd, struct sockaddr_in addr_server);
#endif //_TFTP_H_