linux socket 线程安全,linux下SOCKET深入

#include #include "def.h"

void server_f(int);

void client_f(int);

/*获取文件名的函数*/

char *getfn(char *pathname)

{

int i,j;

for(i=0;pathname[i]!='\0';i++);

for(j=i;pathname[j]!='/';j--);

return(&pathname[j+1]);

}

int main()

{

int sockfd;

char c;

while(1) /*主界面循环*/

{

if((sockfd=socket(PF_INET,SOCK_STREAM,0))==-1) /*socket的建立*/

{

perror("socket");

exit(1);

}

printf("(%d)File system:\n",sockfd);

printf("1.Send\n");

printf("2.Recieve\n");

printf("3.Exit\n");

printf(">");

c=fgetc(stdin);getchar();

if(c=='1') /*选择了client端,负责发送,详见client_f函数*/

{

client_f(sockfd);

close(sockfd);

continue;

}

else if(c=='2') /*选择了server端,负责接收,详见server_f函数*/

{

server_f(sockfd);

close(sockfd);

continue;

}

else if(c=='3') /*退出*/

{

close(sockfd);

break;

}

else /*错误的操作*/

{

printf("Wrong instruction!\n");

close(sockfd);

continue;

}

}

printf("Bye-bye!\n");

exit(0);

}

/*server端作用函数,负责接收数据*/

void server_f(int sockfd)

{

int fd,sin_size,client_fd,recvbytes;

struct sockaddr_in my_addr,opp_addr;

AppPacket info,*pack;

pack=&info;

my_addr.sin_family=PF_INET;

my_addr.sin_port=htons(MYPORT);

my_addr.sin_addr.s_addr=INADDR_ANY;

bzero(&(my_addr.sin_zero),8);

if(bind(sockfd,(struct sockaddr *)&my_addr,sizeof(struct sockaddr))==-1)

{

perror("bind");

close(sockfd);

return;

}

if(listen(sockfd,BACKLOG)==-1)

{

perror("listen");

close(sockfd);

return;

}

printf("Waiting for connection...\n"); /*打印出等待连接信息,并在下面的accept处等待*/

if((client_fd=accept(sockfd,(struct sockaddr *)&opp_addr,&sin_size))==-1)

{

perror("accept");

close(client_fd);

close(sockfd);

return;

}

/*有连接过后先接收一个文件名的信息*/

if(recv(client_fd,pack,sizeof(AppPacket),0)==-1)

{

perror("recv");

close(client_fd);

close(sockfd);

return;

}

if(((pack->tAppPackHead).iFileSize)==0x00) /*判断为文件名确认信息*/

{

char u;

char pathname[100];

int temp;

char *tempbuf;

/*询问是否接收来自[IP]的大小为[大小]的[文件名]文件*/

printf("===From %s===\n",inet_ntoa(opp_addr.sin_addr));

printf("Do you wanna recieve %s ?(y)\n",pack->byData);

printf("SIZE:%d bytes\n",(pack->tAppPackHead).lPayloadLength);/*新加入文件大小信息*/

u=fgetc(stdin);getchar();

if(u=='y'||u=='Y') /*同意接收*/

{

while(1) /*存放地址的循环,带出错重输*/

{

printf("Type your path to place the file:\n");

scanf("%s",pathname);getchar();

strcat(pathname,pack->byData);

if((fd=open(pathname,O_WRONLY|O_CREAT|O_EXCL,0777))<0)

{

perror("open");

continue;

}

else

break;

}

if(send(client_fd,&u,1,0)<0) /*发送'y'或者'Y',告诉client端同意接收了*/

{

perror("Response");

close(fd);

close(client_fd);

close(sockfd);

return;

}

while(1) /*接收循环,以前出错的地方!记住,recv此函数不一定将send来的东西全部读完*/

{

/*先接收发过来的包*/

recvbytes=0;

tempbuf=malloc(sizeof(AppPacket)); /*使用临时缓冲区用来recv循环接收socket来的数据*/

while(recvbytes!= sizeof(AppPacket))/*当接收的数据没有达到预期值时,循环接收*/

{

if((temp=recv(client_fd,tempbuf+recvbytes,sizeof(AppPacket)-recvbytes,0))==-1)

{

perror("recv");

close(client_fd);

close(fd);

close(sockfd);

return;

}

recvbytes+=temp;

//printf("%d\n",recvbytes);

}

memcpy(pack,tempbuf,sizeof(AppPacket));/*把在临时缓冲区的数据拷贝到pack里面形成包*/

free(tempbuf);/*开心的释放:)*/

/*然后在下面进行判断是数据还是已经发完了*/

if(((pack->tAppPackHead).iFileSize)==0x01)/*来的是数据*/

{

write(fd,pack->byData,(pack->tAppPackHead).lPayloadLength);/*写入文件*/

//printf("!\n");

continue;

}

else if(((pack->tAppPackHead).iFileSize)==0x02)/*来的是结束信息*/

{

printf("Recieve ok!\n");

close(client_fd);

close(fd);

close(sockfd);

break;

}

/*出错处理!多亏了最开始还是考虑到了出错的情况,才得以发现问题!

因此养成出错处理是好习惯,尽管有些错逻辑上是不会出现的~*/

else

{

printf("Error.\n");

close(client_fd);

close(fd);

close(sockfd);

return;

}

}

return;

}

else /*不同意接收文件*/

{

if(send(client_fd,&u,1,0)<0)/*发非'y'或'Y'给client端表明不同意接收文件*/

{

perror("Response");

close(fd);

close(client_fd);

close(sockfd);

return;

}

printf("Connection denied...\n");

close(fd);

close(client_fd);

close(sockfd);

return;

}

}

else /*判断文件名验证信息失败,不是我们的写的协议,出错*/

{

printf("File protocol not match!\n");

close(client_fd);

return;

}

}

/*client端处理函数,负责发送文件*/

void client_f(int sockfd)

{

int sendbytes,size,fd;

AppPacket info,*pack;

struct hostent *host;

struct sockaddr_in opp_addr;

char pathname[100];

char dest[48],buf[5];

pack=&info;

/*指明发送文件循环,带出错重输*/

while(1)

{

printf("Please tell me which file do you wanna send:\n");

scanf("%s",pathname);getchar();

if((fd=open(pathname,O_RDONLY,0777))<0)

{

perror("open");

continue;

}

else

{

struct stat stat;

strcpy(pack->byData,getfn(pathname));

(pack->tAppPackHead).iFileSize=0x00;

fstat(fd,&stat);

(pack->tAppPackHead).lPayloadLength=stat.st_size;/*把文件大小信息也装进去*/

break;

}

}

/*指明发送IP循环,带出错重输*/

while(1)

{

printf("And tell me where do you wanna send:\n");

scanf("%s",dest);getchar();

if((host=gethostbyname(dest))==NULL)

{

perror("gethost");

continue;

}

else

break;

}

opp_addr.sin_family=PF_INET;

opp_addr.sin_port=htons(MYPORT);

opp_addr.sin_addr=*((struct in_addr *)host->h_addr);

bzero(&(opp_addr.sin_zero),8);

/*开始连接server端,前提是server端已经准备好,在等待连接状态,否则返回*/

if(connect(sockfd,(struct sockaddr *)&opp_addr,sizeof(struct sockaddr))==-1)

{

perror("connect");

close(fd);

return;

}

/*先把文件名发过去*/

if(send(sockfd,pack,sizeof(AppPacket),0)==-1)

{

perror("send filename");

return;

}

printf("Waiting for response...\n");/*打印等待回应信息,并在下面recy处等待*/

/*接收请求反馈信息*/

char u;

if(recv(sockfd,&u,1,0)==-1)

{

perror("check");

return;

}

if(u=='y'||u=='Y')/*'y'或者'Y'表示同意*/

{

printf("Sending request accept...\n");

sleep(1);//此处就是因为会出现发送接收不同步的情况,所以我先睡1秒,稳一下*/

/*发送数据的循环*/

while((size=read(fd,pack->byData,MAX_LENGTH))>0)

{

(pack->tAppPackHead).iFileSize=0x01;/*因为是数据,所以填1*/

(pack->tAppPackHead).lPayloadLength=size;/*读了多少填多少*/

if(send(sockfd,pack,sizeof(AppPacket),0)<0)

{

perror("send");

close(fd);

return;

}

}

/*发送完毕,发送结束信息给server端*/

memset(pack->byData,0,MAX_LENGTH);

(pack->tAppPackHead).iFileSize=2;/*结束的标志*/

(pack->tAppPackHead).lPayloadLength=-1;/*不需要数据大小,防止出错填-1*/

if(send(sockfd,pack,sizeof(AppPacket),0)<0)

{

perror("send");

close(fd);

return;

}

printf("Send ok!\n");

close(fd);

return;

}

else /*发送请求被驳回...T_T,太冷血了*/

{

printf("Sending request denied...\n");

close(fd);

return;

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值