必须在linux里编译运行,
编译命令cc -o 要生成可执行程序的文件名 要编译的文件名
如:cc -o server server.c
运行时 ./server 参会数
./表示从当前目录搜索
我觉得socket生成的int形的连接号,相当于用open命令返回的int型的文件句柄,就把它当文件一样用服务器写,客户端读出来,再写到本地硬盘上
这里有关shoct编程的一些知识
http://hi.baidu.com/yanzi52351/blog/item/134827d6b806b12806088b21.html
/*
by:yanzi52351
本程序是client端
程序功能:
连接server端接收数据,另存为text2.txt
发送文件在参数中指定
运行参数#./client ip port sendname
ip 服务器ip地址
port 服务器连接端口
sendname 本端要向服务器端要发送的文件名
运行环境:
Linux,UNIX,Windows下的CYGWIN
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#define BUFSIZE 128
#define PERM 0644 /* 创建文件的默认属性*/
#define littleBUFSIZE 126
/*#definechar DATA[]="Half a league, half a league..."*/
main(argc,argv)
int argc
char *argv[]
{
struct hostent *hp,*gethostbyname()
int outfile,infile,msgsock,sock,length,clilen,rval,realn,i=0
ssize_t nread
char buf[BUFSIZE]
char charnum
struct sockaddr_in server,client
if(argc<4)
{
printf("输入的参数不正确\n\n")
printf("运行参数#./server ip port sendname\n")
printf(" ip 服务器ip地址\n")
printf(" port 服务器连接端口\n")
printf(" sendname 本端要向服务器端要发送的文件名\n\n\n")
exit(1)
}
/***************************建立Socket连接*******************************/
sock=socket(AF_INET,SOCK_STREAM,0)/* 申请一个套节字,AF_INET,SOCK_STREAM是指TCP协议*/
if (sock<0)
{
perror("opening stream socket")
exit(1)
}
server.sin_family=AF_INET/*必然的,这里指的是Internet协议*/
hp=gethostbyname(argv[1])/*根据主机名查地址,返回指针指向hostent结构*/
if (hp==0) /*当没有此主机名时*/
{
fprintf(stderr,"%s:unknow host\n",argv[1])
exit(2)
}
memcpy((char *)&server.sin_addr,(char *)hp->h_addr,hp->h_length)/*拷贝Internet地址*/
server.sin_port=htons(atoi(argv[2]))/*argv[2]是端口号,2000-5000都可以,这里,要看server的输出了*/
if (connect(sock,(struct sockaddr *)&server,sizeof server)<0) /*根据server地址连接sock,建立一条真实的连接*/
{
perror("请检查端口是否正确")
exit(1)
}
printf("连接成功\n\n")
/*************************上面建好了Socket连接,下面就是怎么用sock了,和对待文件一样***********/
if((outfile=open("test2.txt",O_WRONLY|O_CREAT|O_TRUNC,PERM))==-1)
{
printf("创建文件出错\n")
exit(1)
}
memset(buf,0,sizeof buf)/*缓冲区清零*/
printf("*****************下面是 client 端接收文件时数据的传送记录*****************\n")
printf("***************** client 端将接收的文件另存为test2.txt *****************\n\n")
while((nread=read(sock,buf,BUFSIZE))>0)/*从sock读取传来的文件内容到缓冲区*/
{
realn=buf[BUFSIZE-2]/*查一下有效内容长度*/
if(realn==-128)
{
printf("文件test2.txt接收完了\n")
break
}
printf("从sock读了第 %3d 块数据,大小是 %3d ,",++i,nread)
realn=buf[BUFSIZE-2]/*查一下有效内容长度*/
printf("有效长度是 %3d ,编号是%c\n\n",realn,buf[BUFSIZE-1])
if(write(outfile,buf,realn)<realn) /*将缓冲区的内容写到文件里*/
printf("写文件时出了错\n")
charnum=buf[BUFSIZE-1]
memset(buf,0,sizeof buf)/*缓冲区清零*/
buf[0]=charnum/*准备告诉对方收到了第几块i+48是i的ASCII值*/
write(sock,buf,BUFSIZE)/*把收到信息发回去*/
}
close(outfile)
/**********************************下面是发送部分****************************************************************/
if((infile=open(argv[3],O_RDONLY))==-1)
{
printf("找不到文件%s或打不开,停止运行\n",argv[3])
exit(1)
}
printf("\n\n\n*****************下面是 client 端发送文件时数据的传送记录*****************\n")
printf("****************** client 端 发送的文件是%13s ****************\n\n",argv[3])
i=0/*****重置计数器*********/
memset(buf,0,sizeof buf)/*缓冲区清零*/
while((nread=read(infile,buf,littleBUFSIZE))>0) /*将文件读到缓冲区*/
{
printf("从文件中读大小为 %3d 的数据,",nread)
buf[littleBUFSIZE]=nread/*把实际大小放在发的数据的最后一位*/
i++
buf[littleBUFSIZE+1]=(i%10)+48/*i+48是i的ASCII值*/
if(write(sock,buf,littleBUFSIZE+2)<=nread)
printf("写sock出了错")
else
printf("往sock发了第 %3d 块,大小是 %3d ,",i,nread)
memset(buf,0,sizeof buf)/*缓冲区清零*/
if(rval=read(sock,buf,littleBUFSIZE+2)<0)
/*从scok读对方收到信息后的应答*/
printf("读sock出了错\n")
else
printf("对方收到块编号 %3s \n\n",buf)
}/*while*/
printf("文件%s发送完毕\n\n",argv[3])
close(infile)
close(sock)
exit(0)
}
/*
by:yanzi52351
本程序是server端
程序功能:
传输一个特定的文件,名字为test.txt
传送完后,开始接收client端发过来的文件
另存收到数据的文件名为是程序的第一个参数
在本端文件是以追加方式打开的
所以会把每次client端传过来的数据都保存起来
而不会清删除以前的
接收完文件后,会继续监听端口,等待client的连接
运行参数#./server savename
savname 存储客户端发过来数据的文件名
运行环境:
Linux,UNIX,Windows下的CYGWIN
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#define TRUE 1
#define littleBUFSIZE 126
#define BUFSIZE 128
#define PERM 0644 /* 创建文件的默认属性*/
/*发的时候是128,*/
main (argc,argv)
int argc
char *argv[]
{
int sock,length,clilen
struct sockaddr_in server,client
int msgsock
struct hostent *hp,*gethostbyname()
int outfile,infile
ssize_t nread
char buf[BUFSIZE]
int rval
int realn
int i=0,j/*小计数器*/
char charnum
if(argc<2)
{
printf("参数不正确\n\n")
printf("运行参数#./server savename\n")
printf(" savname 存储客户端发过来数据的文件名\n\n\n")
exit(1)
}
/******************************建立Socket连接*********************************/
sock=socket(AF_INET,SOCK_STREAM,0)
if (sock<0)
{
perror("opening stream socket")
exit(1)
}
server.sin_family=AF_INET
server.sin_addr.s_addr=INADDR_ANY/*必然的,这里指的是Internet协议*/
server.sin_port=0/*这里,是让系统自动分配一个端口号,在1024到5000之间*/
if (bind(sock,(struct sockaddr *)&server,sizeof server)<0) /*将IP地址和端口号绑到sock上*/
{
perror("binding stream socket")
exit(1)
}
length=sizeof server
if (getsockname(sock,(struct sockaddr *)&server,&length)<0) /*获得指定socket的本地地址,成功返回0,错误返回-1*/
{
perror("getting socket name")
exit(1)
}
printf("Socket port # %d\n",ntohs(server.sin_port))/*打印出系统分的端口号,给client用*/
listen(sock,5)/*5个连接请求排队等待,一般5个*/
do{
printf("正在监听端口 %d ,等待用户连接.要停止此此服务,按CTRL+C\n",ntohs(server.sin_port))
/****************现在是等待客户来连接,如果来客户了,那就建好了socket,就可以当文件使用**********/
clilen=sizeof client
msgsock=accept(sock,(struct sockaddr *)&client,(int *)&clilen)/*创建一个新的与sock相同的socket并返回其值*/
if (msgsock==-1) /*非并发处理,反复型*/
perror("accept")
else
{ /**********这里开始进行文件处理,一直到最后************/
printf("有一个链接接入\n\n")
if((infile=open("test.txt",O_RDONLY))==-1)
{
printf("找不到文件test.txt或打不开,停止运行\n")
exit(1)
}
printf("********************下面是 server 端发送文件时数据的传输记录*****************\n")
printf("******************** server 端发送的文件是test.txt ********************\n\n")
memset(buf,0,sizeof buf)/*缓冲区清零*/
while((nread=read(infile,buf,littleBUFSIZE))>0) /*将文件读到缓冲区*/
{
printf("从文件中读大小为 %3d 的数据,",nread)
buf[littleBUFSIZE]=nread/*把实际大小放在发的数据的最后一位*/
i++
buf[littleBUFSIZE+1]=(i%10)+48/*i+48是i的ASCII值*/
if(write(msgsock,buf,littleBUFSIZE+2)<=nread)
/*将缓冲区的内容写到sock*/
printf("写sock出了错\n")
else
printf("往sock发了第 %3d 块,大小 %3d ,",i,nread)
memset(buf,0,sizeof buf)/*缓冲区清零*/
if(rval=read(msgsock,buf,littleBUFSIZE+2)<0)
/*从scok读对方收到信息后的应答*/
printf("读sock出了错\n")
else
printf("对方收到块编号 %3s \n\n",buf)
}/*while*/
memset(buf,0,sizeof buf)
buf[littleBUFSIZE]=128
write(msgsock,buf,littleBUFSIZE+2)
printf("文件test.txt发送完毕")
close(infile)
}/*else*/
/**************************************************接收文件****************************/
if((outfile=open(argv[1],O_WRONLY|O_CREAT|O_APPEND,PERM))==-1)/*如果文件不存在创建文件,如果存在以追加方式打开*/
{
printf("创建文件出错\n")
exit(1)
}
printf("\n\n\n**************下面是 server 端接收文件时数据的传输记录*************\n")
printf("************ server 端将接收的文件另存为%13s **********\n\n",argv[1])
i=0
memset(buf,0,sizeof buf)/*缓冲区清零*/
while((nread=read(msgsock,buf,BUFSIZE))>0)/*从sock读取传来的文件内容到缓冲区*/
{
printf("从sock读了第 %3d 块数据,大小是 %3d ,",++i,nread)
realn=buf[BUFSIZE-2]/*查一下有效内容长度*/
printf("有效长度是 %3d ,编号是%3c\n\n",realn,buf[BUFSIZE-1])
if(write(outfile,buf,realn)<realn) /*将缓冲区的内容写到文件里*/
printf("写文件时出了错\n")
charnum=buf[BUFSIZE-1]
memset(buf,0,sizeof buf)/*缓冲区清零*/
buf[0]=charnum/*准备告诉对方收到了第几块i+48是i的ASCII值*/
write(msgsock,buf,BUFSIZE)/*把收到信息发回去*/
}
close(outfile)
close(msgsock)
printf("文件%s接收完毕\n\n\n",argv[1])
}
while(1)
exit(0)
}
server.c是服务器端
程序功能:
运行参数#./server savename
savname 存储客户端发过来数据的文件名
传输一个特定的文件,名字为test.txt
传送完后,开始接收client端发过来的文件
另存为savname
在本端文件savname是以追加方式打开的
所以会把每次client端传过来的数据都保存起来
而不会清删除以前的
接收完文件后,会继续监听端口,等待client的连接
client.c是客户端
程序功能:
运行参数#./client ip port sendname
ip 服务器ip地址
port 服务器连接端口
sendname 本端要向服务器端要发送的文件名
连接server端接收数据,另存为text2.txt
发送文件sendname
//通过TCP实现:#define PORT 34000
void SendFile(LPCTSTR strFilename) //参数为发送文件路径及文件名
{
AfxSocketInit(NULL)
CSocket sockSrvr
sockSrvr.Create(PORT)// Creates our server socket
sockSrvr.Listen()// Start listening for the client at PORT
CSocket sockRecv
sockSrvr.Accept(sockRecv)// Use another CSocket to accept the connection
CFile myFile
if(!myFile.Open(strFilename, CFile::modeRead | CFile::typeBinary))
return
int myFileLength = myFile.GetLength()// Going to send the correct File Size
sockRecv.Send(&myFileLength, 4)// 4 bytes long
byte* data = new byte[myFileLength]
myFile.Read(data, myFileLength)
//1024
int iRet
iRet = sockRecv.Send(data, myFileLength)//Send the whole thing now
cout <<"Ret = " <<iRet <<endl
cout <<"send file over!" <<endl
myFile.Close()
delete data
sockRecv.Close()
}
//接收文件
#define PORT 34000
void GetFile(LPCTSTR strFilename) //参数为保存文件的路径及文件名
{
AfxSocketInit(NULL)
CSocket sockClient
sockClient.Create()
sockClient.Connect("127.0.0.1", PORT)// "127.0.0.1" is the IP to your server, same port
int dataLength
sockClient.Receive(&dataLength, 4)//Now we get the File Size first
byte* data = new byte[dataLength]
sockClient.Receive(data, dataLength)//Get the whole thing
CFile destFile(strFilename, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary)
destFile.Write(data, dataLength)// Write it
destFile.Close()
cout <<"Recive file over!" <<endl
delete data
sockClient.Close()
}
楼上已经把如何建立socket说明了,我只讲一下数据封装和传输过程:
1、UDP 137服务已经启动,并且会回应接受的数据包;
2、发送端的应用准备发送的数据;
3、调用socket,指明目标地址和端口(137),源地址和端口可以指定,也可以忽略;
4、socket封装UDP包,增加UDP包头,进而封装IP包,增加IP包头;
5、socket调用底层驱动(链路层),将IP包封装成物理链路上传输的帧,以以太网为例,会增加帧头,包括源MAC和目标MAC,当然中间会用到ARP,解析出IP和MAC的对应关系,由协议栈完成,应用可以不必理会;
6、底层的数据帧通过物理链路传输到对方;
7、对方接收后,反过来从底层向上层,逐渐剥去帧头、IP头、UDP头,得到实际的数据,并根据UDP头部的目标端口,传送给上层的应用,137端口服务;
8、137端口服务处理后,反后头来,发送回应数据,发送过程同上。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)