上交select服务器客户端代码
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <sys/select.h>
#include <sys/time.h>
#define ERR_MSG(msg) do{\
printf("line:%d\n",__LINE__);\
perror(msg);\
}while(0)
#define PORT 1234
#define IP "192.168.10.224"
int main(int argc, const char *argv[])
{
//创建套接字
int cfd=socket(AF_INET,SOCK_STREAM,0);
if(cfd<0)
{
ERR_MSG("socket");
return -1;
}
printf("socket create success cfd=%d __%d__\n",cfd,__LINE__);
struct sockaddr_in sin;
sin.sin_family =AF_INET;
sin.sin_port =htons(PORT);
sin.sin_addr.s_addr =inet_addr(IP);
fd_set readfds,tempfds;
FD_ZERO(&readfds);
FD_ZERO(&tempfds);
FD_SET(0,&readfds);
FD_SET(cfd,&readfds);
//connect
if(connect(cfd,(struct sockaddr*)&sin,sizeof(sin))<0)
{
ERR_MSG("connect");
return -1;
}
printf("connect success\n");
char buf[128]="";
ssize_t res=0;
int s_res=0;
while(1)
{
tempfds=readfds;
s_res=select(cfd+1,&tempfds,NULL,NULL,NULL);
if(s_res<0)
{
ERR_MSG("select");
return -1;
}
else if(0==s_res)
{
printf("time out!\n");
return -1;
}
if(FD_ISSET(0,&tempfds))
{
bzero(buf,sizeof(buf));
printf("请输入:");
scanf("%s",buf);
//send
if(send(cfd,buf,sizeof(buf),0)<0)
{
ERR_MSG("send");
return -1;
}
printf("send success\n");
}
if(FD_ISSET(cfd,&tempfds))
{
//recv
bzero(buf,sizeof(buf));
res=recv(cfd,buf,sizeof(buf),0);
if(res<0)
{
ERR_MSG("recv");
return -1;
}
else if(0==res)
{
printf("服务端下线\n");
break;
}
printf("__%d__\t接收信息: %s\n",__LINE__,buf);
}
}
//关闭文件描述符
if(close(cfd)<0)
{
ERR_MSG("close");
return -1;
}
return 0;
}
poll代码
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <poll.h>
#define ERR_MSG(msg) do{\
printf("line: %d\n", __LINE__); \
perror(msg);\
}while(0)
#define PORT 1234 //端口号的网络字节序 1024~49151
#define IP "192.168.10.224" //ifconfig查看本机IP
int main(int argc, const char *argv[])
{
//创建流式套接字
int cfd = socket(AF_INET, SOCK_STREAM, 0);
if(cfd < 0)
{
ERR_MSG("socket");
return -1;
}
printf("socket create success cfd=%d __%d__\n", cfd, __LINE__);
//功能:允许端口快速被重用,快速被复用
int reuse =1;
if(setsockopt(cfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
{
ERR_MSG("setsockopt");
return -1;
}
//绑定,客户端非必须绑定,
//如果不绑定则程序启动后操作系统会默认绑定一个可用IP和随机端口
//填充服务器的地址信息结构体,给conncet函数使用
//连接哪个服务器,就填哪个服务器的IP和端口
struct sockaddr_in sin;
sin.sin_family = AF_INET; //必须填充AF_INET;
sin.sin_port = htons(PORT); //端口号的网络字节序 1024~49151
sin.sin_addr.s_addr = inet_addr(IP); //ifconfig查看本机IP
//连接到服务器
if(connect(cfd, (struct sockaddr*)&sin, sizeof(sin)) < 0)
{
ERR_MSG("connect");
return -1;
}
printf("服务器连接成功 __%d__\n", __LINE__);
//创建集合
struct pollfd fds[2];
fds[0].fd = 0; //指定要监测0号
fds[0].events = POLLIN; //监测0号文件描述符对应的空间中是否有数据可读
fds[1].fd = cfd;
fds[1].events = POLLIN;
char buf[128] = "";
ssize_t res = 0;
int p_res = 0;
while(1)
{
//阻塞方式监测集合
p_res = poll(fds, 2, -1);
if(p_res < 0)
{
ERR_MSG("poll");
return -1;
}
else if(0 == p_res)
{
printf("time out...\n");
break;
}
//判断0号文件描述符是否有POLLIN事件
if((fds[0].revents & POLLIN) != 0)
{
fgets(buf, sizeof(buf), stdin);
buf[strlen(buf)-1] = 0;
if(send(cfd, buf, sizeof(buf), 0) < 0)
{
ERR_MSG("send");
return -1;
}
printf("发送成功\n");
}
//cfd文件描述符有POLLIN事件
if(fds[1].revents & POLLIN)
{
bzero(buf, sizeof(buf));
//接收数据
res = recv(cfd, buf, sizeof(buf), 0);
if(res < 0)
{
ERR_MSG("recv");
return -1;
}
else if(0 == res)
{
printf("[%s:%d] 服务器下线 __%d__\n",\
inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), __LINE__);
break;
}
printf("[%s:%d] cfd=%d : %s, __%d__\n",\
inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), cfd, buf, __LINE__);
}
}
if(close(cfd) < 0)
{
ERR_MSG("close");
return -1;
}
return 0;
}
tftp服务器上传下载
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/stat.h>
#include <fcntl.h>
#define ERR_MSG(msg) do{\
printf("line=%d\n",__LINE__);\
perror(msg);\
}while(0)
#define PORT 69
#define IP "192.168.10.139"
int download(int sfd,struct sockaddr_in sin);
int upload(int sfd,struct sockaddr_in sin);
int main(int argc, const char *argv[])
{
//创建流式套接字
int sfd=socket(AF_INET,SOCK_DGRAM,0);
if(sfd<0)
{
ERR_MSG("socket");
return -1;
}
printf("socket creat success line = %d\n",__LINE__);
//填充服务器自身的地址信息结构体
//真实的地址信息结构体根据地址族制定 man 7 IP
struct sockaddr_in sin;
sin.sin_family=AF_INET;//必须填充AF_INET
sin.sin_port=htons(PORT);//端口号的网络字节序 1024 ~ 49151
sin.sin_addr.s_addr=inet_addr(IP);// 填充本机IP
int mode=0;
while(1)
{
printf("please input-->");
scanf("%d",&mode);
if(mode==1)
{
download(sfd,sin);
}
else if(mode==2)
{
upload(sfd,sin);
}
}
return 0;
}
int upload(int sfd,struct sockaddr_in sin)
{
char buf[516] = "";
*(short*)buf = htons(2); //操作码1读 2写
char *ptr1 = buf + 2; //文件名
printf("请输入上传的文件名>>>");
char name[128] = "";
scanf("%s", name);
strcpy(ptr1, name);
char *ptr2 = buf + strlen(ptr1) + 3; //模式
strcpy(ptr2, "octet");
int buflen = 2 + strlen(ptr1) + 1 + strlen(ptr2) + 1;
if(sendto(sfd, buf, buflen, 0, (struct sockaddr*)&sin, sizeof(sin)) < 0)
{
ERR_MSG("sendto");
return -1;
}
//收发数据包
struct sockaddr_in recvaddr;
socklen_t addrlen = sizeof(recvaddr);
short opflag = 0;
short req_num = 0; //对方需要的块编号
short snd_num = 0; //己方发送的块编号
ssize_t res = 0;
int fd = open(name, O_RDONLY);
if(fd < 0)
{
ERR_MSG("open");
return -1;
}
//发送上传请求后,对面会回答一个ACK(0)
while(1)
{
//接受应答信息
bzero(buf, sizeof(buf));
res = recvfrom(sfd, buf, sizeof(buf), 0, (struct sockaddr*)&recvaddr, &addrlen);
if(res < 0)
{
ERR_MSG("recvfrom");
return -1;
}
opflag = ntohs(*(short*)buf);
req_num = ntohs(*(short*)(buf+2));
if(4==opflag && req_num==snd_num)
{
//发送数据包
bzero(buf, sizeof(buf));
*(short*)buf = htons(3);
*(short*)(buf+2) = htons(++snd_num);
res = read(fd, buf+4, sizeof(buf)-4);
if(res < 0)
{
ERR_MSG("read");
return -1;
}
else if(res == 0)
{
break;
}
if(sendto(sfd, buf, res+4, 0, (struct sockaddr*)&recvaddr, addrlen) < 0)
{
ERR_MSG("sendto");
return -1;
}
}
else
{
printf("error__%d__\n", __LINE__);
return -1;
}
}
if(close(fd) < 0)
{
ERR_MSG("close");
return -1;
}
printf("上传成功\n");
}
int download(int sfd,struct sockaddr_in sin)
{
//组下载协议
char buf[516]="";
int n;
short int* ptr=(short int *)buf;
*ptr=htons(1);
char *ptr2=buf+2;
//strcpy(ptr2,"1_armcli.c");
strcpy(ptr2,"5.png"); //定义要下载的文件
char *ptr3 = ptr2+strlen(ptr2)+1;
strcpy(ptr3,"octet");
int size=2+strlen(ptr2)+1+strlen(ptr3)+1;
if(sendto(sfd,buf,size,0,(struct sockaddr *)&sin,sizeof(sin))<0) //向服务器发送下载协议
{
ERR_MSG("sendto");
return -1;
}
struct sockaddr_in fake_sin; //定义一个地址结构体变量来接受服务器的IP和临时端口信息
int len=sizeof(fake_sin);
int fd_w=open("./copy.png",O_WRONLY|O_CREAT|O_TRUNC,0664); //将要写入的文件打开
if(fd_w<0)
{
printf("error __%d__\n",__LINE__);
return -1;
}
short int i=0;
int flag=0;
while (1)
{
bzero(buf,sizeof(buf)); //每次循环前将数组清零
//判断每次收到的字节数是否等于516,如果小于516则说明是最后一个数据包,将flag置1
//最后写入一次然后退出循环
if((n=recvfrom(sfd,buf,516,0,(struct sockaddr*)&fake_sin,&len))<516)
flag = 1;
char* ptr4=buf+4;//buf数组前四个字节不属于要写入的数据,直接跳过
int len_buf=n-4; //写入的真实长度
if(write(fd_w,ptr4,len_buf)<0)
{
ERR_MSG("write");
return -1;
}
printf("写入ing\n");
short int ack[2]; //定义一个数组来存储应答信号
short int* ptr5 = (short int*)buf; //用同为两个字节short类型去获取操作码
i = ntohs(*ptr5); //将获取到的操作码由网络字节序转为本机字节序
i++; //操作码自加1
*ptr5 = htons(i); //将自加后的操作码再次转为网络字节序存储到ptr5中
short int* ptr6 = ptr5 + 1; //用ptr6获取buf中存储的块编号
ack[0] = *ptr5;
ack[1] = *ptr6; //拼接应答信号
if (sendto(sfd, ack, sizeof(ack), 0, (struct sockaddr*)&fake_sin, sizeof(fake_sin)) < 0)
{
ERR_MSG("sendto");
return -1;
}
printf("应答\n");
// 如果接收到的数据小于512字节,并且本次接收已经不是完整的512字节,
// 则为最后一包数据,直接退出循环
if (flag == 1 && len_buf < 516 - 4)
break;
}
}