• Linux IPC udp/ip socket 编程


    模型

    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    //服务器:    
    
    socket()              //创建socket			
    struct sockaddr_in    //准备通信地址
    bind()                //绑定socket和addr 
    sendto()/recvfrom     //进行通信
    close()               //关闭socket
    
    //客户端:
    
    socket()              //创建socket:
    //准备通信地址:服务器的地址
    sendto()/recv()       //进行通信:
    close()               //关闭socket:
    

    socket()

    //创建网络端点,返回socket文件描述符,失败返回-1设errno
    int socket(int domain, int type, int protocol);
    

    domain :协议族(protocol family)(网络通讯(IP)还是本地通讯(xxx.socket))

    • AF_INET用于实现给予ipv4网络协议的网络协议
      type :协议(TCP还是UDP)
    • SOCK_DGRAM //数据报套接字, 实现包括但不限于UDP协议, which is不可靠,无连接的数据报通信方
      protocol: 特殊协议, 一般给0

    准备通信地址:

    struct sockaddr{	//主要用于函数的形参类型, 很少定义结构体变量使用, 叫做通用的通信地址类型//$man bind
    	sa_family_t 	sa_family;
    	char        	sa_data[14];
    }
    struct sockaddr_in{	//准备网络通信的通信地址	//$man in.h
    	sa_family_t	sin_family;   	//协议族, 就是socket()的domain的AF_INET
    	in_port_t       sin_port;   //端口号
    	struct in_addr	sin_addr;   //IP地址,
                        //当前网段的最大ip地址是广播地址,即,xxx.xxx.xxx.255。
                        //255.255.255.255在所有网段都是广播地址
    }
    struct in_addr{	
        in_addr_t	s_addr;		//整数类型的IP地址
    }
    

    bind()

    //把通信地址和socket文件描述符绑定,用在服务器端,成功返回0,失败返回-1设errno
    int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
    

    sockfd: socket文件的fd(returned by socket())
    addr: 需要强制类型转换成socketaddr_un或soketaddr_in, 参见上
    addrlen: 通信地址的大小, 使用sizeof();

    sendto()

    //向指定的socket和相应的地址发送消息,成功返回实际发送数据的大小,失败返回-1设errno
    ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
    

    dest_addr:目标地址(收件人信息)
    addrlen: 目标地址的大小

    ANote

    • send(sockfd, buf, len, flags);等价于 sendto(sockfd, buf, len, flags, NULL, 0);
    • recv()/ send()表示通过sockfd收发数据, 因为tcp下, 收发之前sockfd已经和相应的地址连接了,所以不需要指定收发谁的/给谁, 但是udp因为收发时没有连接, 所以需要指定

    recvfrom()

    //从指定的socket和相应的地址接受消息,并提供来电显示的功能,成功返回实际接收的数据大小,失败返回-1设errno
    ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
    

    src_addr: 结构体指针, 用于保存数据发送方的通信地址
    addrlen: 指针类型, 用于保存发送方的地址大小

    Note:

    • recv(sockfd, buf, len, flags); 等价于 recvfrom(sockfd, buf, len, flags, NULL, 0);
    • accept() and recvfrom() 后面的参数是用来提供来电显示的
    • 一个server对应多个client
    • server可以不知道client的地址, 但是client得知道server的地址
    • send data 一定要知道对方地址
    • receive data不需要知道对方地址
    • TCP/IP的socket都是SOCK_STREAM的,全程连接,通过socket就能找到对方地址, send data的话,直接丢给socket就行
    • UDP/IP的socket是SOCK_DGRAM的,不全程连接,不能通过socket找到对方,send data的话,server中需要使用recvfrom()来知道client的地址, 所以肯定要sendto();client本来就知道server的地址, 直接sendto()
    • recvfrom()的唯一意义就是在udp-server中配合sendto()使用
    • 因为不能通过socket找到对方, 只要是udp发消息, 就得通过sendto()
    server
    TCP/IP send();recv()
    UDP/IP recvfrom();sendto()

    例子-一对一的upd/ip协议的服务器模型

    //udp/ip server 五步走
    #include<stdio.h>
    #include<stdlib.h>
    #include<unistd.h>
    #include<sys/types.h>
    #include<sys/socket.h>
    #include<netinet/in.h>
    #include<arpa/inet.h>
    int main(){
    	//1. 创建socket
    	int sockfd=socket(AF_INET,SOCK_DGRAM,0);
    	if(-1==sockfd)
    		perror("socket"),exit(-1);
    	
    	//2. 准备通信地址
    	struct sockaddr_in addr;
    	addr.sin_family=AF_INET;
    	addr.sin_port=htons(8888);
    	addr.sin_addr.s_addr=inet_addr("176.43.11.211");
    
    	//3. 绑定socket和通信地址
    	int res=bind(sockfd,(struct sockaddr*)&addr,sizeof(addr));
    	if(-1==res)
    		perror("bind"),exit(-1);
    	printf("bind success
    ");
    
    	//4. 进行通信
    	char buf[100]={0};
    	struct sockaddr_in recv_addr;		//为使用recvfrom得到client地址做准备, 最终为sendto()做准备
    	socklen_t len=sizeof(recv_addr);
    	res=recvfrom(sockfd,buf,sizeof(buf),0,(struct sockaddr*)&recv_addr,&len);
    	if(-1==res)
    		perror("recvfrom"),exit(-1);
    
    	char* ip=inet_ntoa(recv_addr.sin_addr);				//将recvfrom获得client地址转换成点分十进制字符串
    	printf("data received from client :%s is:%d
    ",ip,res);	
    
    	res=sendto(sockfd,"I received",sizeof("I received"),0,(struct sockaddr*)&recv_addr,len);//使用recvfrom获得的client地址
    	if(-1==res)
    		perror("sendto"),exit(-1);
    
    	//5. 关闭socket
    	res=close(sockfd);
    	if(-1==res)
    		perror("close"),exit(-1);
    	printf("close success
    ");
    		
    	return 0;
    }
    
    
    //udp/ip client
    #include<stdio.h>
    #include<stdlib.h>
    #include<unistd.h>	//close()
    #include<sys/types.h>
    #include<sys/socket.h>
    #include<arpa/inet.h>
    #include<netinet/in.h>
    int main(){
    	int sockfd=socket(AF_INET,SOCK_DGRAM,0);
    	if(-1==sockfd)
    		perror("socket"),exit(-1);
    	printf("create socket succesfully
    ");
    	struct sockaddr_in addr;
    	addr.sin_family=AF_INET;
    	addr.sin_port=htons(8888);
    	addr.sin_addr.s_addr=inet_addr("176.43.11.211");	//这个是server的地址, 虽然没有connect, which means 不能通过socket找到这个地址, 但是我们还是知道这个地址的, sendto()是可以直接用的
    
    	int res=sendto(sockfd,"hello",sizeof("hello"),0,(struct sockaddr*)&addr,sizeof(addr));
    	if(-1==res)
    		perror("sendto"),exit(-1);
    	printf("data sent size:%d
    ",res);
    	char buf[100]={0};
    	res=recv(sockfd,buf,sizeof(buf),0);
    	if(-1==res)
    		perror("recv"),exit(-1);
    	printf("data received from server:%s
    ",buf);
    	res=close(sockfd);
    	if(-1==res)
    		perror("close"),exit(-1);
    
    	return 0;
    }
    
  • 相关阅读:
    七周七语言——Prolog(二)
    centos中使用python遇到的几个问题
    use SWF / Flash in cocos2d-x; cocos2d(cocos2d-x) 直接播放flash / SWF文件
    【C++自我精讲】基础系列二 const
    Find发帖水王哥
    JAVA从零单排之前因
    CSharp
    python实战--Http代理服务器
    有道单词-批量导入[只有单词]
    编译原理(一道小证明题)
  • 原文地址:https://www.cnblogs.com/xiaojiang1025/p/5950461.html
Copyright © 2020-2023  润新知