tftp文件传输客户端:
#include <stdio.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
int down(int sfd, struct sockaddr_in sin);
int up(int sfd, struct sockaddr_in sin);
int main(int argc, const char *argv[])
{
//创建报式套接字
int sfd = socket(AF_INET, SOCK_DGRAM, 0);
if(sfd < 0)
{
perror("socket");
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.8.133");
char c = 0;
while(1)
{
system("clear");
printf("**********************\n");
printf("*******1.下载*********\n");
printf("*******2.上传*********\n");
printf("*******3.退出*********\n");
printf("**********************\n");
printf("请输入>>>");
c = getchar();
while(getchar()!=10);
switch(c)
{
case '1':
down(sfd, sin);
break;
case '2':
up(sfd,sin);
break;
case '3':
goto END;
break;
default:
printf("输入错误,请重新输入\n");
}
printf("输入任意字符回车清屏>>>");
while(getchar() !=10);
}
END:
//关闭文件描述符
close(sfd);
return 0;
}
int down(int sfd, struct sockaddr_in sin)
{
char filename[20] = "";
char buf[516] = "";
bzero(buf, sizeof(buf));
printf("请输入要下载的文件名>>>");
fgets(filename, sizeof(filename), stdin);
filename[strlen(filename)-1] = 0;
//下载请求包
int size = sprintf(buf, "%c%c%s%c%s%c", 0, 1, filename, 0, "octet", 0);
if(sendto(sfd, buf, size, 0, (struct sockaddr*)&sin, sizeof(sin)) < 0)
{
perror("sendto");
return -1;
}
int fd = -1, flag = 0;
socklen_t addrlen = sizeof(sin);
ssize_t res = 0;
unsigned short num = 0;
//循环接收数据包
while(1)
{
bzero(buf, sizeof(buf));
res = recvfrom(sfd, buf, sizeof(buf), 0, (struct sockaddr*)&sin, &addrlen);
if(res < 0)
{
perror("recvfrom");
return -1;
}
if(3 == buf[1])
{
if(htons(num+1) == *(unsigned short*)(buf+2))
{
num++;
if(0 == flag)
{
fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0664);
if(fd < 0)
{
perror("open");
return -1;
}
flag = 1;
}
if(write(fd, buf+4, res-2-2) < 0)
{
perror("write");
return -1;
}
//ACK,
buf[1] = 4;
if(sendto(sfd, buf, 4, 0, (struct sockaddr*)&sin, sizeof(sin)) < 0)
{
perror("sendto");
return -1;
}
if(res-2-2 < 512)
{
printf("%s 文件下载完毕\n", filename);
break;
}
}
}
else if(5 == buf[1])
{
fprintf(stderr, "错误码:%d 错误信息:%s\n", ntohs(*(unsigned short*)(buf+2)), buf+4);
break;
}
}
close(fd);
return 0;
}
int up(int sfd, struct sockaddr_in sin)
{
char name[20] = "";
char buf[516] = "";
int i=1;
ssize_t res=0;
socklen_t len=sizeof(sin);
bzero(buf, sizeof(buf));
printf("请输入要上传的文件名>>>");
fgets(name, sizeof(name), stdin);
name[strlen(name)-1] = 0;
//请求上传
int size = sprintf(buf, "%c%c%s%c%s%c", 0, 2, name, 0, "octet", 0);
if(sendto(sfd, buf, size, 0, (struct sockaddr*)&sin, sizeof(sin)) < 0)
{
perror("sendto");
return -1;
}
int fd=open(name,O_RDONLY);
if(fd<0)
{
perror("open");
return -1;
}
while(1)
{
//保存服务器通信端口
if(recvfrom(sfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,&len)<0)
{
perror("recvfrom");
return -1;
}
//发送包
bzero(buf,sizeof(buf));
buf[1]=3;
*(short*)(buf+2)=htons(i);
i++;
res=read(fd,buf+4,512);
if(res==0)
{
printf("上传成功\n");
break;
}
else if(res<0)
{
perror("read");
return -1;
}
if(sendto(sfd, buf, res+4, 0, (struct sockaddr*)&sin, sizeof(sin)) < 0)
{
perror("sendto");
return -1;
}
}
close(fd);
return -1;
}
接收文件:
上传文件:
多进程:
ser.c;
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
int rcvsend(int sfd_new,struct sockaddr_in cin);
typedef void (*sighandler_t)(int);
void hand(int sig)
{
while(waitpid(-1,NULL,WNOHANG)>0);
}
int main(int argc, const char *argv[])
{
//僵尸进程
sighandler_t s=signal(17,hand);
if(SIG_ERR==s)
{
perror("signal");
return -1;
}
//套接字
int sfd=socket(AF_INET,SOCK_STREAM,0);
if(sfd<0)
{
perror("sfd");
return -1;
}
//如果不加这段代码,则服务器异常退出后,会导致端口号在30s~3min内释放不出来
//当程序结束后,想要让其他进程能够快速复用端口号,就可以使用下面的代码
//允许端口快速被重用
int reuse = 1;
if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse ,sizeof(reuse)) < 0)
{
perror("setsockopt");
return -1;
}
printf("允许端口快速重用\n");
//bind绑定
struct sockaddr_in sin;
sin.sin_family=AF_INET;
sin.sin_port=htons(8888);
sin.sin_addr.s_addr=inet_addr("192.168.8.80");
if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))<0)
{
perror("bind");
return -1;
}
//listen
if(listen(sfd,128)<0)
{
perror("listen");
return -1;
}
printf("服务器监听成功\n");
//accept
struct sockaddr_in cin;
socklen_t len=sizeof(cin);
pid_t pid;
int sfd_new=0;
while(1)
{
sfd_new=accept(sfd,(struct sockaddr*)&cin,&len);
if(sfd_new<0)
{
perror("accept");
return -1;
}
printf("[%s:%d] newfd = %d 连接成功\n", \
inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), sfd_new);
//recv
pid=fork();
if(pid==0)
{
close(sfd);
rcvsend(sfd_new,cin);
}
else if(pid<0)
{
perror("fork");
return -1;
}
close(sfd_new);
}
close(sfd);
return 0;
}
int rcvsend(int sfd_new,struct sockaddr_in cin)
{
char buf[128]="";
ssize_t res=0;
while(1)
{
bzero(buf,sizeof(buf));
res=recv(sfd_new,buf,sizeof(buf),0);
if(res==0)
{
printf("客户端关闭\n");
return -1;
}
else if(res<0)
{
perror("recv");
return -1;
}
printf("[%s:%d] newfd = %d : %s\n", \
inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), sfd_new, buf);
//发送
//将获取到的数据拼接后发送回去
strcat(buf, "*_*");
if(send(sfd_new, buf, sizeof(buf), 0) < 0)
{
perror("sen");
return -1;
}
printf("send success\n");
}
}
多线程 :
ser.c:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include <pthread.h>
void* rcvsend(void* arg);
struct msg
{
int sfd_new;
struct sockaddr_in cin;
};
int main(int argc, const char *argv[])
{
//套接字
int sfd=socket(AF_INET,SOCK_STREAM,0);
if(sfd<0)
{
perror("sfd");
return -1;
}
//如果不加这段代码,则服务器异常退出后,会导致端口号在30s~3min内释放不出来
//当程序结束后,想要让其他进程能够快速复用端口号,就可以使用下面的代码
//允许端口快速被重用
int reuse = 1;
if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse ,sizeof(reuse)) < 0)
{
perror("setsockopt");
return -1;
}
printf("允许端口快速重用\n");
//bind绑定
struct sockaddr_in sin;
sin.sin_family=AF_INET;
sin.sin_port=htons(8888);
sin.sin_addr.s_addr=inet_addr("192.168.8.80");
if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))<0)
{
perror("bind");
return -1;
}
//listen
if(listen(sfd,128)<0)
{
perror("listen");
return -1;
}
printf("服务器监听成功\n");
//accept
struct sockaddr_in cin;
socklen_t len=sizeof(cin);
pid_t pid;
int sfd_new=0;
struct msg info;
while(1)
{
sfd_new=accept(sfd,(struct sockaddr*)&cin,&len);
if(sfd_new<0)
{
perror("accept");
return -1;
}
printf("[%s:%d] newfd = %d 连接成功\n", \
inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), sfd_new);
info.sfd_new=sfd_new;
info.cin=cin;
//线程
pthread_t pid;
//recv
if(pthread_create(&pid,NULL,rcvsend,(void*)&info)<0)
{
perror("pthread_create");
return -1;
}
//分离线程
pthread_detach(pid);
}
close(sfd);
return 0;
}
void* rcvsend(void* arg)
{
char buf[128]="";
ssize_t res=0;
int sfd_new=((struct msg*)arg)->sfd_new;
struct sockaddr_in cin=((struct msg*)arg)->cin;
while(1)
{
bzero(buf,sizeof(buf));
res=recv(sfd_new,buf,sizeof(buf),0);
if(res==0)
{
printf("客户端关闭\n");
break;
}
else if(res<0)
{
perror("recv");
break;
}
printf("[%s:%d] sfd_new = %d : %s\n", \
inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), sfd_new, buf);
//发送
//将获取到的数据拼接后发送回去
strcat(buf, "*_*");
if(send(sfd_new, buf, sizeof(buf), 0) < 0)
{
perror("sen");
break;
}
printf("send success\n");
}
close(sfd_new);
pthread_exit(NULL);
}