《socket传输文件.docx》由会员分享,可在线阅读,更多相关《socket传输文件.docx(9页珍藏版)》请在课桌文档上搜索。
1、使用socket的Linux上的C语言文件传输顺序服务器和客户端示例程序2022-10-1112:55使用socket的Linux上的C语言文件传输顺序服务器和客户端示例程序2022-10-2218:12服务器端程序的编译gcc-Ofile_serverfile_server.c客户端程序的编译gcc-0file_clientfileclient.c服务器程序和客户端程应当分别运行在2台计算机上.服务器端程序的运行,在一个计算机的终端执行./file_server客户端程序的运行,在另一个计算机的终端中执行.file.client运行服务器程序的计算机的IP地址根据提示输入要传输的服务器上的文
2、件,该文件在服务器的运行目录上在实际编程和测试中,可以用2个终端代替2个计算机,这样就可以在一台计算机上测试网络程序,服务器端程序的运行,在一个终端执行./file_server客户端程序的运行,在另一个终端中执行./file_client127.0.0.1说明:存何计算机都可以通过127.0.0.1访问自己.也可以用计算机的实际IP地址代替127.0.0.1/IiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiIiiiiiiiiiiiiiiiii/fileserver.c文件传输顺序服务器示例Illllinilll
3、llllllllllllllllllllllllllllllllllllllllllllllllllllllllIiiiiiiiiiiiiiiiii本文件是服务器的代码/ for sockaddr_in/ for socket/ for socket/ for printf#includettinclude#includeincludeinclude/forexit#include/forbzero*#include#includeincludettinclude*/ttdefineHELLO_WORLD_SERVER_PORT6666#defineLENGTH_OF_LISTEN_QUEUE
4、20ItdefineBUFFER_SIZE1024defineFILENAMEMAXSIZE512intmain(intargc,char*argv)设置一个SOCket地址结构SerVejacIdr,代表服务器internet地址,端structsockaddr_inserver_addr;bzero(&server_addr,sizeof(server-addr);把一段内存区的内容全部设置为0server_addr.sin_family=AFINET;server_addr.sinaddr.s_addr=htons(INDDRANY);server_addr.sin_port-htons
5、(HELLO_WORLD_SERVER_PORT);创建用于internet的流协议(TCP)SoCket,用server_socket代表服务器socketintserver_socket=socket(PF_INET,SOCK_STREAM,0);if(server_socket0)printf(zzCreateSocketFailed!,z);exit(1);)把socket和socket地址结构联系起来if(bind(server_socket,(structsockaddr*)&server_addr,sizeof(server_addr)(printf(zzServerBindPo
6、rt:%dFailed!,z,HELLO_WORLD_SERVER_PORT);exit(1);/server_socket用于监听if(listen(server_socket,LENGTH_OFLISTEN_QUEUE)printf(ServerListenFailed!”);exit(1);while(1)服务器端要向来运行(定义客户端的socket地址结构clientaddrstructsockaddr_inclient_addr;socklen_tlength=sizeof(client_addr);接受一个到server_socket代表的socket的一个连接如果没有连接请求,就
7、等待到有连接请求一这是accept函数的特性/accept函数返回一个新的socket,这个socket(new_serveJSOCket)用于同连接到的客户的通信new_serveJSOCket代表了服务器和客户端之间的一个通信通道/accept函数把连接到的客户端信息填写到客户端的socket地址结构client_addr中intnew_server_socket=accept(server_socket,(structsockaddr*)&c1ient_addr,length);if(newserver_socket0)(printf(zzServerAcceptFailed!nz,);
8、break;)charbufferBUFFER_SIZE;bzero(buffer,BUFFER_SIZE);length-recv(new_server_socket,buffer,BUFFERSIZE,0);if(lengthFILE_NAME_MAX_SIZE?FILE_NAMEJfAX_SIZE:strlen(buffer)f/intfp=open(filename,ORDONLY);/if(fp0)while(file_block_length-fread(buffer,sizeof(char),BUFFER_SIZE,fp)0)printf(,zfiIeblocklength=%d
9、n,z,fiIeblocklength);发送buffer中的字符串到new_serveJSOCket,实际是给客户端if(send(newserversocket,buffer,fileblocklength,0)0)(printf(xzSendFile:t%sFailedn,z,file_name);break;)bzero(buffer,BUFFER_SIZE);/close(fp);fclose(fp);printf(7zFile:t%sTransferFinishedn,z,file_name);)关闭与客户端的连接close(new_server_socket);关闭监听用的soc
10、ketclose(server_socket);return0;)/IiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiIiiiiiiiiiiiiiiiii/fileclient.c文件传输客户端程序示例/III/ for sockaddr_in/ for socket/ for socket/ for printf/ for exit/ for bzeroIiiiiiiiiiiiiiiiii本文件是客户机的代码#include#includeinclude#includeinclude#include*include#inc
11、ludeinclude#include*/defineHELLO_WORLD_SERVER_PORT6666defineBUFFER_SIZE1024defineFILENAMEMAXSIZE512intmain(intargc,char*argv)(if(argc!=2)printf(,Usage:.%sServerIPAddressXnzz,argv0);exit(1);)设置一个socket地址结构CIient_addr,代表客户机internet地址,端structsockaddr_inclient_addr;bzero(&client_addr,sizeof(c1ient_addr)
12、;把一段内存区的内容全部设置为0client_addr.sin_family=AF_INET;/internet协议族client_addr.sin_addr.s_addr=htons(INADDR_ANY);/INADDR_ANY表示自动获取本玩地址client_addr.sin_port=htons(0);/0表示让系统自动分配一个空闲端口创建用于internet的流协议(TCP)SOCket,用client_socket代表客户机socketintclient_socket=socket(F_INET,SOCK_STREAM,0);if(client_socket0)printf(zzC
13、reateSocketFailed!nz,);exit(1);)把客户机的socket和客户机的socket地址结构联系起来if(bind(client_socket,(structsockaddr*)&client_addr,sizeof(client_addr)Printf(ClientBindPortFailed!nzz);exit(1);设置一个socket地址结构serveraddr,代表服务器的internet地址,端口structsockaddr_inserver_addr;bzero(&server_addr,sizeof(serveraddr);serveraddr.sin_
14、family=AFINET;if(inetaton(argv1,&serveraddr.sinaddr)=0)服务器的IP地址来自程序的参数(printf(zzServerIPAddressError!n,z);exit(1);)server_addr.sin_port=htons(HELLO_WORLD_SERVER_PORT);socklentserveraddrlength=sizeof(serveraddr);向服务器发起连接,连接成功后client_socket代表了客户机和服务器的一个socket连接if(connect(client_socket,(structsockaddr*
15、)&server_addr,server_addr_length)BUFFER_SIZE?BUFFER_SIZE:strlen(filename);向服务器发送buffer中的数据send(client_socket,buffer,BUFFER_SIZE,0);/intfp=open(filename,OJVRONLYO_CREAT);/if(fpO)FILE*fp=fopen(filename,zzwzz);if(NULL=fp)(printf(z,File:t%sCanNotOpenToWritenzz,file_name);exit(1);)从服务器接收数据到buffer中bzero(b
16、uffer,BUFFER_SIZE);intlength=O;while(length=recv(client_socket,buffer,BUFFER_SIZE,0)if(length0)printf(,RecieveDataFromServer%sFailed!n,z,argvl);break;)/intwrite_length=write(fp,buffer,length);intwrite_length=fwrite(buffer,sizeof(char),length,fp);if(write_lengthlength)Printf(File:t%sWriteFailednzz,fi
17、lename);break;bzero(buffer,BUFFER_SIZE);)printf(zzRecieveFile:t%sFromServer%sFinishednzz,file_name,argvl);fclose(fp);关闭socketclose(client_socket);return0;网络编程socket之connect函数要:网络端程socketUPi存在一批核心接口,而这批核心接口就是儿个看似荷第的函数尽管实际上这些函数没有一个是简的.connect函数就是这些核心接I的一个函数,它完成主动连接的过程.connect函数的功能是完成一个有连接协议的连接过程,对于TCP
18、来说就是那个三路握手过程,它的函数原里:*includeintconnect(intsockfd,conststructsockaddr*server_addr,socklen_taddrlen)返皿O-成功.-1失败.为了理解connect函数,我们噩要时ConneCl函数的功能进行介绍。connect困数的功能可以用句话来概括,就是完成面向连接的协议的连接过程,它是主要连接的。面向连接的协议,在建立连接的时候总会有方先发送数据,那末谁调用了ConneCt谁就是先发送数据的一方,如此理解connect三个参数是容易了,我必需指定数据发送的地址,同时也必需指定数据从哪里发送,这正好是conne
19、ct的前两个参数,而第三个参数是为第二个参数服务的.参数sockfd指定数据发送的套接字解决从哪里发送的问题.内核需要维护大量IO通道,所以用户必需通过这个参数告诉内核从哪个IO通道,此处就是从哪个socket接【I中发送数据-SoCkfd是先前socket返网的值.参数servcr_addr指定数据发送的目的地,也就是服务器端的地址.这里服务器是针对connect说的,因为connect是主动连接的方调用的,所以楣应的要存在一个被连接的一方,被动连接的一方需要调用listen以接受connect的连接请求,如此被动连接的一方就是服务器了.参数addrlcn指定SerVejHddr结构体的长度
20、.我们知道系统中存在大贵的地址结构,但socket接口只是通过一个统一的结构来指定参数类型,所以需要指定一个长度,以使内核在进行参数亚制的时候有个有个界限.与所有的socket网络接【I一样,connect总会在某个时候可能失败,此时它会返向-1,相应的errno会被设置,用户可能通过这个值确定是哪个错误,常见的错误有对方主机不可达或者超时错误,也可以是府方生机没有相应的进程在对应端11等待.Socket的send()与recv()函数1.Send西数Intsend(SOCKETs,constcharFAR*buf,IntIen1intflags);该函数的第个参数指定发送端套接字描述符:第二
21、个春数指明一个存放应用程序要发送数据的馈冲区:第三个零数指明实际要发送的数粥的字节Sb第四个谷散普通澳0.这里只Ifi述同步Socket(flsend函数的执行流程“当调用该函数时,(1)send先比较待发送数据的长度Ien和食接字s的发送爆冲的长度,如果Ien大于s的发送状冲区的长度,该函数返回SOCKET_ERROR;(2)如果Ien小于或者等于S的发送缓冲区的长度.那末Send先检杳杨议是否正在发送S的发送缓冲中的数据.如果是就等待侍议把数据发送完.如果协议还没有开始发送s的发送爆冲中的数据或者S的发送媛冲中没有数楙,那末Send就比较S的发送纵冲区的利余空间和Ien(3)如果Ien大余
22、空间大小,send就向来等待协议把S的发送线冲中的数据发送完4)如果Ien小于剩余空间大小,send依仅仅把buf中的数据copy到刹余空间里(注意并非Send把S的发送黑冲中的数楙传到连接的另一期的.而是例议传的,send仅仅是把buf中的数第py到s的发送瑞冲区的剩氽空间咀),如果send函数copy数据成功,就返网实际copy的字节5ft,如果sendrcopy数柢时浮现楮误,那末send就返回SOCKET_ERROR:如果send在等待协议传送数据时网络断开的话,那末SenCl函数也返回SOCKET_ERROR.要注意send函数把buf中的数据成功copy到S的发送缓冲的剩余空间里后
23、它就返回了.但是此时这些数据并不定即将被传到连接的另,如果协议在后续的传送过程中浮现网络错误的话,那末下一个Socket函数就会返回SOCKET.ERROR(每一个除send外的Socket函数在执行的最开始总要先等待食按字的发送缓冲中的数抠被协议传送完毕才干继续.如果在等恃时浮现网络错误,那末该SoCket函数就返回SoCKET_ERROR)注意:在UniX系统卜如果Send在等待协议传送数楙时网络断开的话.调用Send的进程会接收到个SlGPIPE信号,进程对该信号的默认处理是进程终止.通过测试发现,异步socket的send函数在网络刚刚断开时还能发送返回相应的字节数.同时使用Sdect
24、检测也是可写的.但是过几秒钟之后,再send就会出Wrr,返回-1Seleet也不能检测出可写了,2.recv函数Intrecv(SOCKETs,charFAR*buf,intlen,intflags);不管是客户还是眼务春应用程序都用recv函数从TCP在接的另一端接收数据该函数的第一个参数指定按收编套接字描述符;第二个参数指明一个煤冲区.该燥冲区用氽存放recv函数接收到的数楙I第二个咨效指明buf的长度:第四个尊数普通应0,这里只描述同步SOCket的recv函数的执行流程。当应用程序调用recv函数时,(1)recv先等恃S的发送陵冲中的数据被协议传送完毕,如果协议在传送S的发送缓冲中
25、的数据时浮现网络错误,那末recv函数返网SOCKET_ERROR.(2)如果s的发送馈冲中没有数据或者数据被协议成功发送完毕后,recv先检近套接字S的接收i冲区,如果S接收馈冲区中没有数据或者协议正在接收数据,那末起cv就向来等待,直到协议把数据接收完毕,当协议把数据接收完毕,2cv函数就把s的接收煤冲中的数第copyfJbuf中(注遨协议按收到的数据可能大于buf的长度.所以在这种情况下要调用几次recv函数才T把s的接收馈冲中的数据copy完.recv函数仅仅是copy数据.班正的接收数据是协议未完成的).recv由数返回其实际CoPy的字节数.如果recvcopy11lltft.那末它返回SOCKET_ERROR:如果recv函数在等待协议接收数据时网络中断了.那么它诋回0.注廊在UniX系统下,如果recv腐也在等待协议接收数据时网拈断开了,那末闻UrecV的进程会接收到一个SIGPlPe信号,进程对该信号的戳认处理是进程终止.