• Linux网络编程


    前言:整理下Linux下socket编程相关的一下API和知识点

    流式套接字处理流程                                                                                                    

     数据报套接字处理流程

    字节序:字节序有大端小端之分,不同的处理架构在存储一个多字节数字时,若低内存地址存储该数字高位部分,则叫大端字节序,反之则叫小端字节序。因此,为了统一网络中传输的数据的字节序,有了网络序,发送到网络中的数据必须采用网络序。

    主机字节序转网络字节序的函数

    #include <arpa/inet.h>

    uint32_t htonl(uint32_t t)       //h代表host主机字节序,n代表net网络字节序,l代表long类型,s代表short类型 //将主机字节序转成网络字节序

    uint16_t htons(uint16_t t)

    uint32_t ntohl(uint32_t t)    //将网络字节序转成主机字节序

    uint16_t ntohs(uint16_t t)

    地址格式:连接主机的地址的一个抽象

    struct sockaddr{

    unsigned short sa_family ; //地址协议族,一般为AF_INET,代表IPv4协议

    char sa_data[14];    

    };

    该结构不好用,所以有另一个结构

    struct sockaddr_in{

    short int  sin_family ; //地址协议族,一般为AF_INET,代表IPv4协议

    unsigned short int sin_port;  //端口号,为0表示随机选一个端口

    struct in_addr sin_addr;  //IP地址  INADDR_ANY 表示使用自己的IP地址

    unsigned char sin_zero[8];  //添0,为了和sockaddr一样大

    };

    struct in_addr{

    unsigned long s_addr;

    };

    IP地址转换:

    #include <sys/socket.h>

    #include <netinet/in.h>

    #include <arpa/inet.h>

    in_addr_t inet_addr(const char *cp);

    //将ip地址字符串转换为相应的类型,转换后已是网络序,出错返回-1,即255.255.255.255

    char * inet_nota(struct in_addr);

    //将IP地址转换为字符串

    int inet_pton(int af,const char* src,void* dst); 

    将ip地址字符串转换为相应的类型,转换后已是网络序,使用方式例子:inet_pton(AF_INET,ip,&address.sin_addr),成功返回1,失败返回0,并置errno

    const char* inet_ntop(int af,cosnt void* src,char* dst,socklen_t cnt);

    将ip转换为字符串,cnt可以是INET_ADDRSTRLEN(16),INET6_ADDRSTRLEN(46);失败返回NULL。

    套接字类型:SOCK_STREAM流式套接字采用tcp协议,可靠的,面向连接的字节流服务。SOCK_DGRAM数据报套接字,面向无连接的,不可靠的数据报服务。还有一个原始套接字,用于协议开发,比较底层。

    socket函数

    #include <sys/types.h>

    #include <sys/socket.h>

    int socket(int domain,int type,int protocol);

    //domain 协议族,type套接字类型,protocol一般为0,返回一个套接子描述符,相当于文件描述符出错返回-1

    bind函数:将套接字描述符,绑定到地址上

    #include <sys/types.h>

    #include <sys/socket.h>

    int bind(int sockfd,struct sockaddr *my_addr,int addrlen); //sockfd套接字描述符,addrlen为sizeof(struct sockaddr)

    connect函数

    #include <sys/types.h>

    #include <sys/socket.h>

    int connect(int sockfd,struct sockaddr *serv_addr,int addrlen);

    listen函数

    #include <sys/types.h>

    #include <sys/socket.h>

    int listen(int sockfd,int backlog);  //backlog表示未经过处理的连接请求队列可以容纳的最大数目,一般设为5-10之间的数

    accept函数

    #include <sys/socket.h>

    int accept(int sockfd,void *addr,int *addrlen);//sockfd正在listen的一个套接字描述符,addr指向struct sockaddr类型的指针,用来存储远程连接端点的地址,addrlen地址的长度,返回远程端点地址的套接字描述符。

    接受消息,发送消息的函数

    #include <sys/types.h>

    #include <sys/socket.h>

    int send(int sockfd,const void *msg,int len,int flags);

    //sockfd远程连接的套接字描述符,msg指向一个消息结构体的指针,len消息的字节个数,flags一般为0,返回发送的数据的长度。send函数有大小限制,如果发送的数据过多,可以分多次发送。

    int recv(int sockfd,void *buf,int len,unsigned flags);//返回buf的长度,

    以上2个函数用于流式套接字

    int sendto(int sockfd,const void *msg,int len,unsigned int flags,const struct sockaddr *to,int tolen);

    //sockfd远程主机的套接字,sockaddr 远程主机的地址

    int recvfrom(int sockfd,void *buf,int len,unsigned int flags, struct sockaddr *from,int *fromlen);

    这2个函数用数据报套接字

    close和shutdown函数

    close(sockfd)  //关闭套接字,套接字将不允许进行读写操作

    #include <sys/socket.h>

    int shutdown(int sockfd,int how)//how:0表示不允许接受数据,1,表示不允许发送数据,2和colse一样。

    //tcpserver.c
    #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <unistd.h> #include <sys/wait.h> #define PORT 4008 #define BACKLOG 10 #define BUFSIZE 4096 void process(char * cmd); int main(int argc,char* argv[]) { int lsockfd,rsockfd; struct sockaddr_in lsocket,rsocket; if((lsockfd=socket(AF_INET,SOCK_STREAM,0))<0) //服务器端套接字 { perror("socket"); exit(1); } lsocket.sin_family=AF_INET; //设置服务器端地址 lsocket.sin_port=htons(PORT); lsocket.sin_addr.s_addr=INADDR_ANY; bzero(&(lsocket.sin_zero),8); if(bind(lsockfd,(struct sockaddr *)&lsocket,sizeof(struct sockaddr))<0) //将服务器端地址与套接字绑定 { perror("bind"); exit(1); } if(listen(lsockfd,BACKLOG)<0) //监听服务器端套接字,若有客户端connect,则将其加入监听队列 { perror("listen"); exit(1); } int sin_size=sizeof(struct sockaddr); int count=0; while(1) { printf("wait for connecting!\n"); if((rsockfd=accept(lsockfd,(struct sockaddr *)&rsocket,&sin_size))<0) //处理客户端请求 { perror("accept"); continue; } count++; printf("someone connect!,current people %d\n",count); if(!fork()) //为么一个客户端建立一个处理子进程,用来收发数据 { char str[BUFSIZE]; int numbytes=0; while(1) { if((numbytes=recv(rsockfd,str,BUFSIZE-1,0))<0) { perror("recv"); break; } str[numbytes]='\0'; if(strcmp(str,"quit")==0) { printf("client quit!\n"); break; } printf("receive a message: %s\n",str); if(send(rsockfd,str,strlen(str),0)<0) { perror("send"); break; } } close(rsockfd); exit(0); } while(waitpid(-1,NULL,WNOHANG)>0) //此处不会阻塞若第三个参数为WUNTRACED则会阻塞,若有客户端子进程退出,则输出相关语句 { count--; printf("someone quit!,current people have %d\n",count); } } return 0; }
    //tcpclient.c gcc tcpclient.c -o tcpclient  运行tcpclient 127.0.0.1 //输入quit退出
    #include <stdio.h> #include <stdlib.h> #include <string.h> #include <netdb.h> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #define PORT 4008 #define MAXDATASIZE 4096 #define BUFSIZE 4096 int main(int argc,char *argv[]) { int rsockfd; struct sockaddr_in rsocket; if(argc!=2) { fprintf(stderr,"usage:client hostname\n"); exit(1); } if((rsockfd=socket(AF_INET,SOCK_STREAM,0))<0) //创建一个服务器端套接字 { perror("sock"); exit(1); } rsocket.sin_family=AF_INET; //设置服务器端地址 rsocket.sin_port=htons(PORT); rsocket.sin_addr.s_addr=inet_addr(argv[1]); // if(inet_pton(AF_INET,argv[1],&rsocket.sin_addr)<0) // { // perror("inet_pton"); // exit(1); // } // rsocket.sin_addr=*(struct in_addr*)he->h_addr; bzero(&(rsocket.sin_zero),8); if(connect(rsockfd,(struct sockaddr*)&rsocket,sizeof(struct sockaddr))<0) //连接服务器 { perror("connect"); exit(1); } char sstr[BUFSIZE]; char rstr[BUFSIZE]; while(1) //收发数据,输入quit退出 { printf("%15s","command is: "); int len=0; fgets(sstr,BUFSIZE,stdin); sstr[strlen(sstr)-1]=0; if(send(rsockfd,sstr,strlen(sstr),0)<0) { perror("send"); continue; } if(strcmp(sstr,"quit")==0) break; int numbytes=0; if((numbytes=recv(rsockfd,rstr,BUFSIZE-1,0))<0) { perror("recv"); continue; } rstr[numbytes]='\0'; printf("%15s%s\n","result is: ",rstr); } close(rsockfd); return 0; }

     

  • 相关阅读:
    iptables在不重新编译内核以及iptables的情况下 加载iptables模块--在proxmox5中没有测试成功
    ip rule以及ip route的使用--非常重要,需要持续研究!!
    debian版本的相关说明
    分析 linux服务器单网卡在可配置多网关 提供服务的可能性--重要!!!!!
    关于pn定期执行的相关问题分析
    man在线手册-推荐使用debian官方网站
    牛客网暑期ACM多校训练营(第三场) J Distance to Work 计算几何求圆与多边形相交面积模板
    杭电多校第二场 hdu 6315 Naive Operations 线段树变形
    牛客网暑期ACM多校训练营(第三场) A PACM Team 01背包 记录路径
    牛客网暑期ACM多校训练营(第三场) E Sort String 哈希处理字符串(模板)
  • 原文地址:https://www.cnblogs.com/CodingUniversal/p/7424666.html
Copyright © 2020-2023  润新知