基于UDP的TFTP文件传输
#include<myhead.h>
#define SER_PORT 69
#define SER_IP "10.80.17.61"
int main(int argc, const char *argv[])
{
int cfd = socket(AF_INET,SOCK_DGRAM,0);
if(cfd == -1)
{
perror("socket error");
return -1;
}
while(1)
{
int menu = 0;
printf("******************\n");
printf("******1.上传******\n");
printf("******2.下载******\n");
printf("******3.退出******\n");
printf("******************\n");
printf("请输入>>>");
scanf("%d",&menu);
getchar();
switch (menu)
{
case 1:
{
char file_name[128] = "";
char buf[516] = "";
printf("请输入文件名:");
fgets(file_name,sizeof(file_name),stdin);
file_name[strlen(file_name) - 1] = 0;
int fd = open(file_name,O_RDONLY); //打开文件
if(fd == -1)
{
perror("open error");
return -1;
}
short *p1 = (short *)buf; //操作码
*p1 = htons(2);
char *p2 = (char *)buf + 2; //文件名
strcpy(p2,file_name);
char *p3 = p2 + strlen(p2) + 1; //模式位
strcpy(p3,"octet");
int size = 2 + strlen(p2) + strlen(p3) + 2; //请求包的总长度
//将请求包发送给服务器
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(SER_PORT);
sin.sin_addr.s_addr = inet_addr(SER_IP);
sendto(cfd,buf,size,0,(struct sockaddr*)&sin,sizeof(sin));
int i = 0;
while(1)
{
bzero(buf,sizeof(buf)); //清空容器来接受ACK
struct sockaddr_in cin;
socklen_t addrlen = sizeof(cin);
recvfrom(cfd,buf,sizeof(buf),0,(struct sockaddr*)&cin,&addrlen); //接收ACK
short *op = (short *)buf;
short *block_num = op + 1;
int blknum = 1 + i;
i++;
char *data = buf + 4;
if(ntohs(*op) == 4) //判断操作码是否为4
{
bzero(buf,sizeof(buf));
*op = htons(3);
int res = 0;
char transbuf[512] = "";
*block_num = htons(blknum);
res = read(fd,transbuf,512);
if(res == 512)
{
memcpy(data,transbuf,res);
sendto(cfd,buf,sizeof(buf),0,(struct sockaddr*)&cin,sizeof(cin));
}
else if(res < 512)
{
memcpy(data,transbuf,res);
sendto(cfd,buf,res+4,0,(struct sockaddr*)&cin,sizeof(cin));
recvfrom(cfd,buf,sizeof(buf),0,(struct sockaddr*)&cin,&addrlen); //接收ACK
close(fd);
printf("上传完成\n");
break;
}
}
else if(ntohs(*op) == 5)
{
printf("%s\n",data);
close(fd);
break;
}
}
}
break;
case 2:
{
char file_name[128] = "";
char buf[516] = "";
printf("请输入文件名:");
fgets(file_name,sizeof(file_name),stdin);
file_name[strlen(file_name) - 1] = 0;
int fd = open(file_name,O_WRONLY|O_APPEND|O_CREAT,0664); //打开文件
if(fd == -1)
{
perror("open error");
return -1;
}
short *p1 = (short *)buf; //操作码
*p1 = htons(1);
char *p2 = (char *)buf + 2; //文件名
strcpy(p2,file_name);
char *p3 = p2 + strlen(p2) + 1; //模式位
strcpy(p3,"octet");
int size = 2 + strlen(p2) + strlen(p3) + 2; //请求包的总长度
//将请求包发送给服务器
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(SER_PORT);
sin.sin_addr.s_addr = inet_addr(SER_IP);
sendto(cfd,buf,size,0,(struct sockaddr*)&sin,sizeof(sin));
while(1)
{
bzero(buf,sizeof(buf)); //清空容器来接受数据包
struct sockaddr_in cin;
socklen_t addrlen = sizeof(cin);
int res = 0;
res = recvfrom(cfd,buf,sizeof(buf),0,(struct sockaddr*)&cin,&addrlen); //接收数据包
res = res - 4;
short *op = (short *)buf;
short *block_num = op + 1;
short blknum = ntohs(*block_num);
char *data = buf + 4;
if(ntohs(*op) == 3) //判断操作码是否为3
{
if(res == 512) //判断数据是否为512
{
write(fd,data,res);
bzero(buf,sizeof(buf));
short *ack = (short *)buf;
*ack = htons(4); //将操作码置为4
*block_num = htons(blknum); //把块编号转变成网络字节序
sendto(cfd,buf,4,0,(struct sockaddr*)&cin,sizeof(cin)); //发送ACK
}
else if(res < 512) //如果数据小于512,说明最后一段数据接收完毕
{
write(fd,data,res); //将数据写入文件
bzero(buf,sizeof(buf)); //清空容器
short *ack = (short *)buf;
*ack = htons(4); //将操作码置为4
*block_num = htons(blknum); //把块编号转变成网络字节序
sendto(cfd,buf,4,0,(struct sockaddr*)&cin,sizeof(cin)); //发送ACK
printf("下载完成\n");
close(fd);
break;
}
}
else if(ntohs(*op) == 5)
{
printf("%s\n",data);
close(fd);
break;
}
}
}
break;
case 3:
{
close(cfd);
return 0;
}
break;
}
}
return 0;
}
基于UDP的网络聊天室
项目需求:
-
如果有用户登录,其他用户可以收到这个人的登录信息
-
如果有人发送信息,其他用户可以收到这个人的群聊信息
-
如果有人下线,其他用户可以收到这个人的下线信息
-
服务器可以发送系统信息
list.h
#ifndef LIST_H
#define LIST_H
#include<myhead.h>
typedef struct Node //服务器接收消息
{
char usrName[20];
int len;
struct sockaddr_in cin;
struct Node *next;
}Node,*NodePtr;
struct msgTyp //发送端消息
{
char type;
char usrName[20];
char msgText[1024];
};
NodePtr create();
int empty(NodePtr L);
NodePtr apply_node(char *usrName,struct sockaddr_in *cin);
int insert(NodePtr L,char *usrName,struct sockaddr_in *cin);
int search_value(NodePtr L,char *usrName);
int list_delete(NodePtr L,int pos);
#endif
list.c
#include"list.h"
NodePtr create()
{
NodePtr L = (NodePtr)malloc(sizeof(Node));
if(NULL == L)
{
printf("创建失败\n");
return NULL;
}
strcpy(L->usrName,"");
L->len = 0;
L->next = NULL;
printf("创建成功\n");
return L;
}
int empty(NodePtr L)
{
return L->next == NULL;
}
NodePtr apply_node(char *usrName,struct sockaddr_in *cin)
{
NodePtr p = (NodePtr)malloc(sizeof(Node));
if(NULL == p)
{
printf("申请节点失败\n");
return NULL;
}
strcpy(p->usrName,usrName);
p->next = NULL;
p->cin = *cin;
return p;
}
int insert(NodePtr L,char *usrName,struct sockaddr_in *cin)
{
if(NULL == L)
{
printf("链表不合法\n");
return -1;
}
NodePtr p = apply_node(usrName,cin);
if(NULL == p)
{
return -1;
}
p->next = L->next;
L->next = p;
L->len++;
return 0;
}
int search_value(NodePtr L,char *usrName)
{
if(NULL == L||empty(L))
{
printf("查找失败\n");
return -1;
}
NodePtr q = L->next;
for(int i=1;i<=L->len;i++)
{
if(strcmp(q->usrName,usrName)==0)
{
return i;
}
q = q->next;
}
printf("没找到\n");
return -1;
}
int list_delete(NodePtr L,int pos)
{
NodePtr q = L;
for(int i=1;i<pos;i++)
{
q=q->next;
}
NodePtr p = q->next;
q->next = q->next->next;
free(p);
p = NULL;
L->len--;
return 0;
}
client.c
#include"list.h"
#define SER_PORT 9999
#define SER_IP "10.80.21.14"
void *task(void *arg) //此线程完成客户端接受工作,也可接收服务器消息
{
while(1)
{
int cfd = *(int *)arg;
struct sockaddr_in cin;
socklen_t addrlen = sizeof(cin);
char buf[128] = "";
recvfrom(cfd,buf,sizeof(buf),0,(struct sockaddr*)&cin,&addrlen);
printf("%s\n",buf);
bzero(buf,sizeof(buf));
}
pthread_exit(NULL);
}
int main(int argc, const char *argv[])
{
int cfd = socket(AF_INET,SOCK_DGRAM,0);
if(cfd == -1)
{
perror("socket error");
return -1;
}
printf("cfd = %d\n",cfd);
//char buf[128] = "";
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(SER_PORT);
sin.sin_addr.s_addr = inet_addr(SER_IP);
pthread_t tid = -1;
if(pthread_create(&tid,NULL,task,&cfd) != 0)
{
printf("pthread_create error\n");
return -1;
}
pthread_detach(tid);
struct msgTyp msg1;
printf("请输入姓名>>>");
fgets(msg1.usrName,sizeof(msg1.usrName),stdin);
msg1.usrName[strlen(msg1.usrName)-1] = 0;
msg1.type = 'L'; //进入进程后先打一次L标签
sendto(cfd,&msg1,sizeof(msg1),0,(struct sockaddr*)&sin,sizeof(sin));
while(1)
{
struct msgTyp msg2;
fgets(msg2.msgText,sizeof(msg2.msgText),stdin);
msg2.msgText[strlen(msg2.msgText) - 1] = 0;
strcpy(msg2.usrName,msg1.usrName);
if(strcmp(msg2.msgText,"quit") == 0) //输入quit表示退出客户端,并打上Q的标签
{
msg2.type = 'Q';
sendto(cfd,&msg2,sizeof(msg2),0,(struct sockaddr*)&sin,sizeof(sin));
break;
}
msg2.type = 'C'; //打上C标签表示对话信息
sendto(cfd,&msg2,sizeof(msg2),0,(struct sockaddr*)&sin,sizeof(sin));
}
close(cfd);
return 0;
}
server.c
#include"list.h"
#define SER_PORT 9999
#define SER_IP "10.80.21.14"
struct SYS
{
int sfd;
NodePtr L;
};
void *task(void *arg)
{
while(1)
{
NodePtr L = ((struct SYS*)arg)->L;
int sfd = ((struct SYS*)arg)->sfd;
NodePtr q = L;
char buf[128] = "";
bzero(buf,sizeof(buf));
fgets(buf,sizeof(buf),stdin);
buf[strlen(buf) - 1] = 0;
while(q != NULL)
{
sendto(sfd,buf,strlen(buf),0,(struct sockaddr *)&q->cin,sizeof(q->cin));
q = q->next;
}
}
pthread_exit(NULL);
}
int main(int argc, const char *argv[])
{
int sfd = socket(AF_INET,SOCK_DGRAM,0);
if(sfd == -1)
{
perror("socket error");
return -1;
}
printf("sfd = %d\n",sfd);
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(SER_PORT);
sin.sin_addr.s_addr = inet_addr(SER_IP);
if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin)) == -1)
{
perror("bind error");
return -1;
}
printf("bind success\n");
//char buf[128] = "";
struct sockaddr_in cin;
socklen_t addrlen = sizeof(cin);
NodePtr L = create();
pthread_t tid = -1;
struct SYS sys = {sfd,L};
if(pthread_create(&tid,NULL,task,&sys) != 0)
{
printf("pthread_create error\n");
return -1;
}
pthread_detach(tid);
while(1)
{
struct msgTyp msg;
recvfrom(sfd,&msg,sizeof(msg),0,(struct sockaddr*)&cin,&addrlen);
if(msg.type == 'L')
{
insert(L,msg.usrName,&cin);
// printf("%s\n",L->next->usrName);
char buf[128] = "";
printf("%s [%s:%d]登陆成功\n",msg.usrName,inet_ntoa(cin.sin_addr),ntohs(cin.sin_port));
if(L->len != 0)
{
NodePtr q = L->next;
bzero(buf,sizeof(buf));
strcat(buf,"-----");
strcat(buf,msg.usrName);
strcat(buf,"登陆成功-----");
while(q->next != NULL)
{
q = q->next;
sendto(sfd,buf,strlen(buf),0,(struct sockaddr *)&(q->cin),sizeof(q->cin));
}
}
}
else if(msg.type == 'C')
{
NodePtr q = L->next;
while(q != NULL)
{
if(strcmp(q->usrName,msg.usrName)==0)
{
q = q->next;
continue;
}
sendto(sfd,msg.msgText,strlen(msg.msgText),0,(struct sockaddr *)&(q->cin),sizeof(q->cin));
q = q->next;
}
}
else if(msg.type == 'Q')
{
char buf[128] = "";
strcat(buf,"-----");
strcat(buf,msg.usrName);
strcat(buf," 已下线-----");
NodePtr q = L->next;
while(q != NULL)
{
if(strcmp(q->usrName,msg.usrName)==0)
{
q = q->next;
continue;
}
sendto(sfd,buf,strlen(buf),0,(struct sockaddr*)&(q->cin),sizeof(q->cin));
q = q->next;
}
int pos = search_value(L,msg.usrName);
list_delete(L,pos);
}
}
close(sfd);
return 0;
}