[关闭]
@rfish 2015-09-10T03:08:51.000000Z 字数 2829 阅读 2010

socket编程

培训



1. 基本概念

1.1 类型

用文件描述符创建套接字。

类型 特点 说明
流式socket TCP
数据包socket UDP

1.2 点分-二进制 转换

1.2.1 点分转二进制

只能转换ipv4

  1. typedef uint32_t in_addr_t;
  2. struct in_addr {
  3. in_addr_t s_addr;
  4. };
  5. //----------inet_aton
  6. int inet_aton(const char *cp/*点分ip*/
  7. , struct in_addr *inp /*存放转换后的二进制地址*/
  8. );
  9. //----------inet_addr
  10. in_addr_t inet_addr(const char *cp);/*传入需要转换的点分ip*/
  11. //先声明in_addr结构体,然后取其中的s_addr来保存返回值。

1.2.2 二进制转点分

  1. char *inet_ntoa(struct in_addr in);

传入保存二进制地址的结构体,返回点分字符串。

1.2.3 ntoa ntop的关系

都是二进制转点分式。但是:

ntoa类函数 只能转换32位的ipv4地址
ntop类函数 能转换ipv4和ipv6地址

1.3 端口号

short ,16位

1.4 大端,小端

转换函数:

  1. #include <arpa/inet.h>
  2. uint32_t htonl(uint32_t hostlong);
  3. uint16_t htons(uint16_t hostshort);
  4. uint32_t ntohl(uint32_t netlong);
  5. uint16_t ntohs(uint16_t netshort);

程序函数转化后就是大端序列。有端口号就必须用大端。

注意:
在使用时,由于cup的不一样,有的是大端,有的是小端,所有为了代码的移植性,均转换为网络序使用

1.5 TCP socket流程

Created with Raphaël 2.1.2socketservice?setsockoptbindlinsten acceptrecvsendcloseconnectyesno

1.6 问题

  1. 当客户端保持着与服务器端的连接,这时服务器端断开,再开启服务器时会出现: Address already in usr

解决:
可以用netstat -anp | more 可以看到客户端还保持着与服务器的连接(还在使用服务器bind的端口)。这是由于client没有执行close,连接还会等待client的FIN包一段时间。解决方法是使用setsockopt,使得socket可以被重用,是最常用的服务器编程要点。具体的做法为是,在socket调用和bind调用之间加上一段对socket的设置:Address already in use的解决方法

  1. buff重用问题

解决:
每次使用前将buff清零,不然打印出来可能会有乱码。因为没有\0


2. UDP/广播/组播

2.1 UDP流程

Created with Raphaël 2.1.2udp流程socket(数据报)service?bind(port,本机IP)recvfromclosesendto yesno
  1. #include <sys/types.h>
  2. #include <sys/socket.h>
  3. ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);
  4. ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);

2.2 广播

udp协议实现,将数据发送本网段的广播地址。

本机宏定义IP地址
INADDR_ANY

是用于多IP机器上

比如你的机器有三个ip
192.168.1.1
202.202.202.202
61.1.2.3
如果你serv.sin_addr.s_addr=inet_addr("192.168.1.1");
然后监听100端口
这时其他机器只有connect 192.168.1.1:100才能成功。
connect 202.202.202.202:100和connect 61.1.2.3:100都会失败。
如果serv.sin_addr.s_addr=htonl(INADDR_ANY); 的话,无论连接哪个ip都可以连上的。

2.2.1 流程

Created with Raphaël 2.1.2socket(udp)广播方?设置允许发送广播(setsockopt)sendto(ip为广播地址,port需要设置)closebind(绑定端口,和本机所有ip)recvyesno
  1. int on =1;
  2. setsockopt(sockfd,SOL_SOCKET,SO_BROADCAST, )

2.3 组播

用D类地址描述组播编号
例如:230.1.1.1

默认组播打开的

Created with Raphaël 2.1.2start socket(数据报类型)接收方?setsockopt(加入组播组)bind(port,ip=INADDR_ANY)recvfromclosesendto(接收方port,IP=组播ip)yesno

加入组播地址。

  1. struct ip_mreq{
  2. struct in_addr imr_multiaddr;
  3. struct in_addr imr_interface;
  4. };//该结构体库文件已经声明过,可以直接用
  5. struct ip_mreq mreq;
  6. bzero(&mreq,sizeof(mreq));
  7. mreq.imr_multiaddr.s_addr=inet_addr("组播地址");
  8. mreq.imr_interface.s_addr=htol(INADDR_ANY);
  9. /*
  10. inet_pton(AF_INET,"192.168.7.89",(void*)&mreq.imr_interface);//本条和上一条代码效果相同,二选一
  11. */
  12. setsockopt(sockfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq));

注意:

在数据链路层中的目标mac地址为:
mac总共:48bit/6byte

24位 1位 23位
0x01005E 0 组播ip地址低23位

也就是只匹配了组播地址的低23位,到网络层,会再次匹配组播地址。

3. 多路复用

3.1 IO模型

4. shell编程

5. 项目飞秋

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注