




已阅读5页,还剩13页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Socket编程1、 建立socket.Socket是一种文件描述符。Socket也具有一个类似于打开文件的函数调用Socket(),该函数返 回一个整型的Socket描述符,随后的连接建立、数据传输等操作都是通过该Socket实现的。常用的Socket类型有两种:流式Socket (SOCK_STREAM)和数据报式Socket(SOCK_DGRAM)。流式是一种面向连接的Socket,针对于面向连接的TCP服务应用;数据 报式Socket是一种无连接的Socket,对应于无连接的UDP服务应用。int socket(int domain, int type, int protocol);domain指明所使用的协议族,通常为PF_INET,表示互联网协议族(TCP/IP协议族);type参数指定socket的类型: SOCK_STREAM 或SOCK_DGRAM,Socket接口还定义了原始Socket(SOCK_RAW),允许程序使用低层协议;protocol通常赋值0。 Socket()调用返回一个整型socket描述符,你可以在后面的调用使用它。Socket描述符是一个指向内部数据结构的指针,它指向描述符表入口。调用Socket函数时,socket执行体将建立一个Socket,实际上建立一个Socket意味着为一个Socket数据结构分配存储空间。Socket执行体为你管理描述符表。两个网络程序之间的一个网络连接包括五种信息:通信协议、本地协议地址、本地主机端口、远端主机地址和远端协议端口。Socket数据结构中包含这五种信息。2、 Socket配置 面向连接的socket客户端通过 调用Connect函数在socket数据结构中保存本地和远端信息。无连接socket的客户端和服务端以及面向连接socket的服务端通过调用 bind函数来配置本地信息。Bind函数将socket与本机上的一个端口相关联,随后你就可以在该端口监听服务请求。Bind函数原型为:int bind(int sockfd,struct sockaddr *my_addr, int addrlen);Sockfd是调用socket函数返回的socket描述符,my_addr是一个指向包含有本机IP地址及端口号等信息的sockaddr类型的指针;addrlen常被设置为sizeof(struct sockaddr)。struct sockaddr结构类型是用来保存socket信息的: struct sockaddr unsigned short sa_family; /* 地址族, AF_xxx */ char sa_data14; /* 14 字节的协议地址 */;sa_family一般为AF_INET,代表Internet(TCP/IP)地址族;sa_data则包含该socket的IP地址和端口号。另外还有一种结构类型: struct sockaddr_in short int sin_family; /* 地址族 */ unsigned short int sin_port; /* 端口号 */ struct in_addr sin_addr; /* IP地址 */ unsigned char sin_zero8; /* 填充0 以保持与struct sockaddr同样大小 */ ;struct in_addr就是32位IP地址。struct in_addr unsigned long s_addr;这个结构更方便使用。sin_zero用来将sockaddr_in结构填充到与struct sockaddr同样的长度,可以用bzero()或memset()函数将其置为零。指向sockaddr_in 的指针和指向sockaddr的指针可以相互转换,这意味着如果一个函数所需参数类型是sockaddr时,你可以在函数调用的时候将一个指向 sockaddr_in的指针转换为指向sockaddr的指针;或者相反。使用bind函数时,可以用下面的赋值实现自动获得本机IP地址和随机获取一个没有被占用的端口号: my_addr.sin_port = 0; /* 系统随机选择一个未被使用的端口号 */ my_addr.sin_addr.s_addr = INADDR_ANY; /* 填入本机IP地址 */通过将my_addr.sin_port置为0,函数会自动为你选择一个未占用的端口来使用。同样,通过将my_addr.sin_addr.s_addr置为INADDR_ANY,系统会自动填入本机IP地址。注意在使用bind函数是需要将sin_port和sin_addr转换成为网络字节优先顺序;而sin_ zero则不需要转换。计算机数据存储有两种字节优先顺序:高位字节优先和低位字节优先。Internet上数据以高位字节优先顺序在网络上传输,所以对于在内部是以低位字节优先方式存储数据的机器,在Internet上传输数据时就需要进行转换,否则就会出现数据不一致。 下面是几个字节顺序转换函数:htonl():把32位值从主机字节序转换成网络字节序htons():把16位值从主机字节序转换成网络字节序ntohl():把32位值从网络字节序转换成主机字节序ntohs():把16位值从网络字节序转换成主机字节序 Bind()函数在成功被调用时返回0;出现错误时返回-1并将errno置为相应的错误号。需要注意的是,在调用bind函数时一般不要将端口号置为小于1024的值,因为1到1024是保留端口号,你可以选择大于1024中的任何一个没有被占用的端口号。3、连接建立面向连接的客户程序使用Connect函数来配置socket并与远端服务器建立一个TCP连接,其函数原型为: int connect(int sockfd, struct sockaddr *serv_addr,int addrlen);Sockfd 是socket函数返回的socket描述符;serv_addr是包含远端主机IP地址和端口号的指针;addrlen是远端地址结构的长度。 Connect函数在出现错误时返回-1,并且设置errno为相应的错误码。进行客户端程序设计无须调用bind(),因为这种情况下只需知道目的机器 的IP地址,而客户通过哪个端口与服务器建立连接并不需要关心,socket执行体为你的程序自动选择一个未被占用的端口,并通知你的程序数据什么时候到达端口。Connect函数启动和远端主机的直接连接。只有面向连接的客户程序使用socket时才需要将此socket与远端主机相连。无连接协议从不建立直接连接。面向连接的服务器也从不启动一个连接,它只是被动的在协议端口监听客户的请求。Listen函数使socket处于被动的监听模式,并为该socket建立一个输入数据队列,将到达的服务请求保存在此队列中,直到程序处理它们。 int listen(int sockfd, int backlog);Sockfd 是Socket系统调用返回的socket 描述符;backlog指定在请求队列中允许的最大请求数,进入的连接请求将在队列中等待accept()它们。Backlog对队列中等待 服务的请求的数目进行了限制,大多数系统缺省值为20。如果一个服务请求到来时,输入队列已满,该socket将拒绝连接请求,客户将收到一个出错信息。当出现错误时listen函数返回-1,并置相应的errno错误码。 accept()函数让服务器接收客户的连接请求。在建立好输入队列后,服务器就调用accept函数,然后睡眠并等待客户的连接请求。 int accept(int sockfd, struct sockaddr *addr, int *addrlen); sockfd是被监听的socket描述符,addr通常是一个指向sockaddr_in变量的指针,该变量用来存放提出连接请求服务的主机的信息(某台主机从某个端口发出该请求);addrten通常为一个指向值为sizeof(struct sockaddr_in)的整型指针变量。出现错误时accept函数返回-1并置相应的errno值。首先,当accept函数监视的 socket收到连接请求时,socket执行体将建立一个新的socket,执行体将这个新socket和请求连接进程的地址联系起来,收到服务请求的初始socket仍可以继续在以前的 socket上监听,同时可以在新的socket描述符上进行数据传输操作。4、 数据传输Send()和recv()这两个函数用于面向连接的socket上进行数据传输。 Send()函数原型为: int send(int sockfd, const void *msg, int len, int flags);Sockfd是你想用来传输数据的socket描述符;msg是一个指向要发送数据的指针;Len是以字节为单位的数据的长度;flags一般情况下置为0(关于该参数的用法可参照man手册)。 Send()函数返回实际上发送出的字节数,可能会少于你希望发送的数据。在程序中应该将send()的返回值与欲发送的字节数进行比较。当send()返回值与len不匹配时,应该对这种情况进行处理。recv()函数原型为: int recv(int sockfd,void *buf,int len,unsigned int flags); Sockfd是接受数据的socket描述符;buf 是存放接收数据的缓冲区;len是缓冲的长度。Flags也被置为0。Recv()返回实际上接收的字节数,当出现错误时,返回-1并置相应的errno值。Sendto()和recvfrom()用于在无连接的数据报socket方式下进行数据传输。由于本地socket并没有与远端机器建立连接,所以在发送数据时应指明目的地址。sendto()函数原型为: int sendto(int sockfd, const void *msg,int len,unsigned int flags,const struct sockaddr *to, int tolen);该函数比send()函数多了两个参数,to表示目地机的IP地址和端口号信息,而tolen常常被赋值为sizeof (struct sockaddr)。Sendto 函数也返回实际发送的数据字节长度或在出现发送错误时返回-1。 Recvfrom()函数原型为: int recvfrom(int sockfd,void *buf,int len,unsigned int flags,struct sockaddr *from,int *fromlen); from是一个struct sockaddr类型的变量,该变量保存源机的IP地址及端口号。fromlen常置为sizeof (struct sockaddr),在调用时该函数时,一定要先置fromlen的值,否则函数调用会失败。当recvfrom()返回时,fromlen包含实际存入from中的数据字节数。Recvfrom()函数返回接收到的字节数或 当出现错误时返回-1,并置相应的errno。如果你对数据报socket调用了connect()函数时,你也可以利用send()和recv()进行数据传输,但该socket仍然是数据报socket,并且利用传输层的UDP服务。但在发送或接收数据报时,内核会自动为之加上目的地和源地址信息。5、 结束传输当所有的数据操作结束以后,你可以调用close()函数来释放该socket,从而停止在该socket上的任何数据操作:close(sockfd);你也可以调用shutdown()函数来关闭该socket。该函数允许你只停止在某个方向上的数据传输,而另一个方向上的数据传输继续进行。如你可以关闭某socket的写操作而允许继续在该socket上接受数据,直至读入所有数据。int shutdown(int sockfd,int how); Sockfd是需要关闭的socket的描述符。参数 how允许为shutdown操作选择以下几种方式: 0-不允许继续接收数据 1-不允许继续发送数据 2-不允许继续发送和接收数据, 均为允许则调用close () shutdown在操作成功时返回0,在出现错误时返回-1并置相应errno。Tcp通信模型针对本程序的流程图如下:/*struct sockaddr结构类型是用来保存socket信息的:struct sockaddr unsigned short sa_family; /* 地址族, AF_xxx */ char sa_data14; /* 14 字节的协议地址 */ ;struct sockaddr_in结构体如下:struct sockaddr_in short int sin_family; /* 地址族 */unsigned short int sin_port; /* 端口号 */ struct in_addr sin_addr; /* IP地址 */ unsigned char sin_zero8; /* 填充0 以保持与struct sockaddr同样大小 */ ;*/Tcp 服务器端#include #include #include #include #include #include #include #include #define SERVPORT 3333#define BACKLOG 10int main()int sockfd,client_fd,sin_size;struct sockaddr_in my_addr;struct sockaddr_in remote_addr;int len;char buf100;/* 创建socket*/if(sockfd = socket(AF_INET,SOCK_STREAM,0) = -1)perror(socket 创建出错!n);exit(1);/*把创建的socket与本机上的一个端口相关联。*/my_addr.sin_family = AF_INET;my_addr.sin_port = htons(SERVPORT);my_addr.sin_addr.s_addr = INADDR_ANY; / 宏INADDR_ANY 是 0bzero(&(my_addr.sin_zero),8);if(bind(sockfd,(struct sockaddr *)&my_addr,sizeof(struct sockaddr) = -1)perror(bind 出错.n);exit(1);/*使该socket处于被动的监听模式,并为该socket建立一个输入数据队列,将到达的服务请求保存在此队列中,直到程序处理它们。*/if(listen(sockfd,BACKLOG) = -1) perror(listen 出错.n);exit(1);while(1)sin_size = sizeof(struct sockaddr_in);/*在建立好输入队列后,服务器就调用accept函数接收客户的连接请求,然后睡眠并等待客户的连接请求。当accept函数监视的 socket收到连接请求时,socket执行体将建立一个新的socket,执行体将这个新socket和请求连接进程的地址联系起来,收到服务请求的 初始socket仍可以继续在之前的监听,同时在新的socket上进行数据传输操作。*/if(client_fd = accept(sockfd,(struct sockaddr *)&remote_addr,&sin_size) = -1)perror(accept出错.n);continue;printf(received a connection from %sn,inet_ntoa(remote_addr.sin_addr);/*Fork一个新进程,在子进程中进行接收和发送消息。在子进程进行发送/接收消息时,父进程可以同时接受客户端的连接。*/if(!fork()/* 发送“Hello,you are connected!”消息到客户端*/if(send(client_fd,Hello,you are connected!n,26,0) = -1)perror(send 出错!n);/* 接收客户发来的消息,接收的消息存储在buf中,该buf的大小为100字节。*/if(len= recv(client_fd,buf,100,0) = -1)perror(recv 出错!n);buflen = 0;printf(received: %sn,buf);close(client_fd);exit(0);close(client_fd);/* gethostbyname() 通过域名或主机名获取IP地址#include #include struct hostent *gethostbyname(const char *name); 这个函数的传入值是域名或者主机名,例如等等。传出值,是一个hostent的结构。如果函数调用失败,将返回NULL。struct hostent char *h_name; char *h_aliases; int h_addrtype; int h_length; char *h_addr_list; #define h_addr h_addr_list0 ;hostent-h_name 表示的是主机的规范名。例如的规范名其实是。 hostent-h_aliases 表示的是主机的别名.就是google他自己的别名。有的时候,有的主机可能有好几个别名,这些,其实都是为了易于用户记忆而为自己的网站多取的名字。 hostent-h_addrtype 表示的是主机ip地址的类型,到底是ipv4(AF_INET),还是pv6(AF_INET6) hostent-h_length 表示的是主机ip地址的长度 hostent-h_addr_lisst 表示的是主机的ip地址,注意,这个是以网络字节序存储的。千万不要直接用printf带%s参数来打这个东西,会有问题的哇。所以到真正需要打印出这个IP的话,需要调用inet_ntop()。*/Tcp客户端#include #include #include #include #include #include #include #include #define SERVPORT 3333#define MAXDATASIZE 100 int main(int argc,char *argv)int sockfd,recvbytes,sendbytes;char bufMAXDATASIZE;struct hostent *host;struct sockaddr_in serv_addr;if(argc h_addr);printf(serv_addr.sin_addr.s_addr = %xn,serv_addr.sin_addr.s_addr);bzero(&(serv_addr.sin_zero),8);/* Serv_addr参数要指明连接的服务端的IP地址,端口号。*/if(connect(sockfd,(struct sockaddr*)&serv_addr,sizeof(struct sockaddr) = -1)perror(connect 出错!n);exit(1);/*接收服务端发来的消息,存放在buf中,该buf的大小是MAXDATASIZE。*/if(recvbytes = recv(sockfd,buf,MAXDATASIZE,0) = -1)perror(recv 出错!n);exit(1);bufrecvbytes = 0;printf(Received: %s,buf);/*发送消息到服务端。*/if(send(sockfd,hello,Im clientn,30,0) = -1)perror(send error.n); /*消息发送完后,停止连接,关闭该socket。*/close(sockfd);return 0;Udp通信模型针对本程序的流程图如下:Udp 服务器端#include #include #include #include #include #include #define MAXLINE 1024 #define SERV_PORT 8000struct MSG_PACK char cmd; char status; short int len;struct host char UserName20; char Host20; char IP20; char PassWord 20; char SubNet512; char Mode; char ConState; char Pin20; char ConTrol; char RandPassword10;int main(void) int sockfd; struct sockaddr_in servaddr, cliaddr; char mesgMAXLINE; struct MSG_PACK pocket; struct host sHost2 ; socklen_t len; int n;/*创建数据报式socket,指明使用的是tcp/ip协议族*/ sockfd = socket(AF_INET, SOCK_DGRAM, 0); /* create a socket */ /* 把socket与本机上指定端口绑定(相关联)*/ bzero(&servaddr, sizeof(servaddr); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = INADDR_ANY; servaddr.sin_port = htons(SERV_PORT); /* servaddr参数指定相关联的IP地址及端口,并指明是tcp/ip地址族。 */ if(bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr) = -1) perror(bind error); exit(1); len = sizeof(cliaddr);/*服务端循环接收来自客户端的信息。*/ for(;) /* 接收来自客户端的信息,信息存放在mesg中,mesg的大小是MAXLINE,cliaddr参数用来存放请求连接的客户的IP地址及端口号等信息*/ n = recvfrom(sockfd, mesg, MAXLINE, 0, (struct sockaddr *)&cliaddr, &len); printf (n:%d len=%dn,n,len); memcpy(&pocket,mesg,sizeof(struct MSG_PACK);memcpy(&sHost2 , mesg + sizeof(struct MSG_PACK) , sizeof(struct host); printf($n-pocket1-%dn,pocket.cmd); printf(-pocket2-%dn,pocket.status); printf(-pocket3-%dn$n,pocket.len);printf(&n-sHost1-%sn,sHost2.UserName); printf(-sHost2-%sn,sHost2.Host); printf(-sHost3-%sn,sHost2.IP); printf(-sHost4-%sn,sHost2.PassWord); printf(-sHost5-%sn,sHost2.SubNet); printf(-sHost6-%dn,sHost2.Mode); printf(-sHost7-%dn,sHost2.ConState); printf(-sHost8-%sn,sHost2.Pin);printf(-sHost9-%dn,sHost2.ConTrol); printf(-sHost10-%sn&n,sHost2.RandPassword); /* 发送同样的消息给客户端,cliaddr参数中指明了客户端的IP及端口号。 */ n = sendto(sockfd, mesg, n, 0, (struct sockaddr *)&cliaddr, len); close(sockfd); return 0;Udp客户端#include #include #include #include #include #include #include #include #define minornode 0 /从节点向主节点发送连接请求#define hostnode_return 1 /主节点响应从节点的请求#define minornode_change 2 /从节点向主节点发送更新请求#define hostnode_returnchange 3 /主节点响应更新请求 /包头的定义 struct MSG_PACK char cmd; char status; short int len; ; /定义host struct host char UserName20; char Host20; char IP20; char PassWord 20; char SubNet512; char Mode; char ConState; char Pin20; char ConTrol; char RandPassword10; ;int main() char sentbuf1024; struct host newhost; struct MSG_PACK newpack;int iLen;int sock;struct sockaddr_in servaddr;struct sockaddr_in fromAddr;unsigned int fromLen; char recvBuffer1024;struct MSG_PACK pocket;struct host sHost2 ; memset(&newhost,0,sizeof(struct host); strcpy(newhost.UserName,aaaa); strcpy(newhost.Host,www); strcpy(newhost.IP,); strcpy(newhost.PassWord,1111); strcpy(newhost.SubNet,); newhost.Mode=0; newhost.ConState=1; strcpy(newhost.Pin,20); newhost.ConTrol=0; strcpy(newhost.RandPassword,122122); newpack.cmd=1; newpack.status=1; newpack.len=sizeof(newhost); memcpy(sentbuf,&newpack,sizeof(struct MSG_PACK); memcpy(sentbuf+sizeof(struct MSG_PACK),&newhost,sizeof(struct host); iLen =
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 昆明幼儿师范高等专科学校《专业英语及科技论文写作》2023-2024学年第一学期期末试卷
- 东北林业大学《纺织品艺术染色》2023-2024学年第一学期期末试卷
- 福建省福州市八县一中联考2025年高三4月高考二模物理试题含解析
- 四川轻化工大学《复合材料C》2023-2024学年第二学期期末试卷
- 山西省大同市2024-2025学年高三下学期第二次仿真模拟物理试题含解析
- 广东财贸职业学院《航海英语阅读》2023-2024学年第二学期期末试卷
- 福福建省泉州市2024-2025学年高三下学期一诊模拟物理试题含解析
- 云南能源职业技术学院《大学日语4》2023-2024学年第二学期期末试卷
- 南通职业大学《运输组织学》2023-2024学年第二学期期末试卷
- 安徽省安庆市潜山市第二中学2024-2025学年高三预测密卷(新课标II卷)语文试题试卷含解析
- 2024年中考化学复习教学建议-把握中考方向、共研备考策略课件
- 拼多多民事起诉状模板
- 【数字普惠金融的发展研究-以蚂蚁集团为例12000字(论文)】
- 挖机上楼拆迁施工方案
- 2023版个人征信模板简版(可编辑-带水印)
- 外教社新编英语语法教程(第6版)PPT课件Unit-22
- 2023年陕西特岗学前教育学科真题真题
- 痕迹检验概述
- 2023年迎春杯五年级初赛
- 公司报检单模板
- GB/T 9115.4-2000环连接面对焊钢制管法兰
评论
0/150
提交评论