广播
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#define MSG_ERR(msg)do{\
fprintf(stderr,"line:%d",__LINE__);\
perror("msg");\
}while(0);
int main(int argc, const char *argv[])
{
//创建报式套接字
int sfd=socket(AF_INET,SOCK_DGRAM,0);
if(sfd<0){
MSG_ERR("socket");
return -1;
}
//填充发送端的IP和端口号用于bind函数绑定
struct sockaddr_in cin;
cin.sin_family =AF_INET;
cin.sin_port =htons(7777);
cin.sin_addr.s_addr =inet_addr("192.168.250.255");
if(bind(sfd,(struct sockaddr*)&cin,sizeof(cin))<0){
MSG_ERR("bind");
return -1;
}
printf("bind success\n");
//设置允许广播
int set_broad=1;
if(setsockopt(sfd,SOL_SOCKET,SO_BROADCAST,&set_broad,sizeof(set_broad))<0){
MSG_ERR("setbroadopt");
return -1;
}
printf("set broadcast success\n");
//填充接收端的IP和端口号,用于sendto 函数的时候发送给服务器使用
struct sockaddr_in sin;
sin.sin_family =AF_INET;
sin.sin_port =htons(9999);
sin.sin_addr.s_addr =inet_addr("192.168.150.255");
struct sockaddr_in rcvaddr;
socklen_t addrlen=sizeof(rcvaddr);
char buf[128]="";
ssize_t res=0;
while(1){
//从终端获取数据发送给服务器
printf("请输入:");
fgets(buf,sizeof(buf),stdin);
buf[strlen(buf)-1]=0;
//发送数据给服务器,地址信息结构体应该填服务器的地址信息
if(sendto(sfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,sizeof(sin))<0){
MSG_ERR("sendto");
return -1;
}
printf("send success\n");
}
//关闭文件描述符
close(sfd);
return 0;
}
tftp的上传下载
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <string.h>
#include <unistd.h>
#define MSG_ERR(msg)do{\
fprintf(stderr,"line:%d",__LINE__);\
perror("msg");\
}while(0);
int do_download(int sfd,struct sockaddr_in sin);
int main(int argc, const char *argv[])
{
//创建报式套接字
int sfd=socket(AF_INET,SOCK_DGRAM,0);
if(sfd<0){
MSG_ERR("socket");
return -1;
}
//填充服务器IP和的端口供于bind函数绑定
struct sockaddr_in cin;
cin.sin_family =AF_INET;
cin.sin_port =htons(8888);
cin.sin_addr.s_addr =inet_addr("192.168.250.135");//客户端运行所在IP
if(bind(sfd,(struct sockaddr*)&cin,sizeof(cin))<0){
MSG_ERR("bind");
return -1;
}
printf("bind success\n");
//填充服务器的IP和端口,供于下面sendto的函数发送给服务器的时候使用
struct sockaddr_in sin;
sin.sin_family =AF_INET;
sin.sin_port =htons(69);
sin.sin_addr.s_addr =inet_addr("192.168.255.135");
//选择上传还是下载,或者退出
char c=0;
while(1){
printf("--------------------------\n");
printf("----------1.上传----------\n");
printf("----------2.下载----------\n");
printf("----------3.退出----------\n");
printf("--------------------------\n");
printf("请输入--->");
c=getchar();
while(getchar()!=10);
switch(c){
case'1':
//do_upload;
break;
case'2':
do_download(sfd,sin);
break;
case'3':
goto END;//少用goto 会破坏程序结构
break;
default:
printf("Put error,please put again!\n");
}
}
END:
//关闭文件描述符
close(sfd);
return 0;
}
int do_download(int sfd,struct sockaddr_in sin){
//组下载请求包,发送给服务器,服务器在69号端口等待请求
char buf[520]="";
unsigned short *pa=(unsigned short*)buf;
*pa =htons(1);//代表下载操作码
printf("请输入文件名:");
char name[20]="";
scanf("%s",name);
char *pb=buf+2;
strcpy(pb,name);
char *pd=pb+strlen(pb)+1;
strcpy(pd,"octet");
int size=2+strlen(pb)+7;
//发送协议
if(sendto(sfd,buf,size,0,(struct sockaddr*)&sin,sizeof(sin))<0){
MSG_ERR("sendto");
return -1;
}
printf("download request success\n");
socklen_t addrlen=sizeof(sin);
ssize_t res=0;
unsigned short num=0;
while(1){
bzero(buf,sizeof(buf));
//循环接收数据包,地址信息结构体必须接,后续要将ack发给临时端口
res=recvfrom(sfd,buf,516,0,(struct sockaddr*)&sin,&addrlen);
if(res<0){
MSG_ERR("recvfrom");
return -1;
}
//由于发送回来的操作码都是网络字节序,所有有效的操作码都存储在buf[1]的位置
//只要判断buf[1]是3还是5即可
if(3==buf[1]){ // 数据包
//由于UDP可能丢失,或者重复到达,所以需要在每次接收到数据包的时候
//判断一下这个包是不是我需要的,通过快编号判断
if(num+1==ntohs(*(unsigned short*)(buf+2))){
//处理数据,数据首地址在buf+4的位置上
printf("%s",buf+4);//修改成写入到文件中
fflush(stdout);
//回复ACK
buf[1]=4;
if(sendto(sfd,buf,4,0,(struct sockaddr*)&sin,sizeof(sin))<0){
MSG_ERR("sendto");
return -1;
}
//如果数据小于512个字节,则传输结束
if(res-2-2<512){
printf("Send msg over!\n");
break;
}
num++;
}
}
else if(5==buf[1]) //错误报
{
printf("ERROR:%s\n",buf+4);
return -2;
}
}
return 0;
}