网络编程实践使用

242 阅读4分钟

4月「掘金·日新计划」第11天

一、网络编程

socket编程,相关函数套接字

二、实践使用

2.1、套接字api,socket,bind,listen,accept,connect

int socket(int domain,int typeint protocol)

功能:创建套接字

参数:

  1. 所使用的协议族,通常使用AF_TNET,表示IPv4因特网域

    1. AF_INET,IPv4因特网域
    2. AF_INET6,IPv6因特网域
    3. AF_UNIX,域
    4. AF_ROUTE,路由套接字
    5. AF_KEY,密钥套接字
    6. AF_UNSPEC,未指定
  2. 指定socket类型

    1. SOCK_STREAM:TCP
    2. SOCK_DGRAM:UDP
    3. SOCK_RAW:直接访问IP或ICMP,通常用于协议开发
  3. 通常0,选择tpye类型对应的默认协议(结合参数12)

    1. IPPROTO_TCP
    2. IPPROTO_UDP
    3. IPPROTO_SCTP
    4. IPPROTO_TIPC

返回值:网络描述符,错误-1

int bind(int sockfd,const struct sockaddr* addr,socklen_t addr len)

功能:绑定IP地址和端口号

参数:

  1. 网络描述符

  2. 包含IP和端口号的结构体指针struct sockaddr

    1. 协议族

    2. 端口号(要转换网络字节序)

    3. IP地址结构体sockaddr_in(需要强转为struct sockaddr)

      1. sin_family,AF_INET,IP v4
      2. sin_port,端口号(转网络字节序htons(8888))
      3. sin_addr.s_addr,ip地址(转网络字节序inet_aton("192.",struct in_addr地址))
    4. 没有实际意义,只为跟sockaddr内存对齐,这样才能转换,不需要配置

      //ipv4对应
      struct sockaddr_in {
        __kernel_sa_family_t  sin_family;     /* Address family               */
        __be16                sin_port;       /* Port number                  */
        struct in_addr        sin_addr;       /* Internet address             */
      ​
        /* Pad to size of `struct sockaddr'. */
        unsigned char         __pad[__SOCK_SIZE__ - sizeof(short int) -
                              sizeof(unsigned short int) - sizeof(struct in_addr)];
      };
      ​
      struct in_addr {
              __be32  s_addr;
      };
      
  3. 参数2占用字节个数sizeof

int listen(int sockfd,int backlog)

功能:监听,用于服务器端,设置处理最大连接数

参数:

  1. 网络描述符
  2. 最大连接数
int accept(int sockfd,struct sockaddr* addr,socklen_t* addrlen)

功能:连接,服务器端,阻塞等待

参数:

  1. 网络描述符
  2. 客户端的地址结构体,不关心NULL
  3. 参数结构体的长度地址变量(变量int),不关心NULL

返回值:新的套接字描述符,用于读写操作

int connect(int sockfd,const struct sockaddr* addr,socklen_t addrlen)

功能:连接,客户端

参数:

  1. 服务器端的网络描述符(socket
  2. 服务端的IP和端口号结构体指针
  3. 参数2结构体的内存大小sizeof

返回值:失败返回-1,errno看错误代码

2.2、其他inet_aton,inet_ntoa,send,recv,htons,htonl,ntohs,ntohl

int inet_aton(const char* straddr,struct in_addr* addrp)
charinet_ntoa(struct in_addr inaddr)
    
inet_aton("192.168.1.1",&s_addr.sin_addr);

功能:转换字节序

  1. 把字符串形式192.168.1.111转换为网络格式
  2. 把网络形式的IP转换为字符串形式

参数:

  1. ip地址
  2. struct in_addr
read()
write()
ssize_t send(int s,const void* msg,ssize_t len,int flags)
ssize_t recv(int s,void* buf,ssize_t len,int flags)

功能:数据收发(UDP用secvmsg,sendmsg,recvfrom,sendto)

最后一个参数设置阻塞,一般0

uint16_t htons(uint16_t host16bitvalue)//本地转网络h to n
uint32_t htonl(uint32_t host32bitvalue)uint16_t ntohs(uint16_t net16bitvalue)
uint32_t ntohl(uint32_t net32bitvalue)

功能:

  1. 返回网络字节序(大端字节序)
  2. 返回主机字节序

h代表host(主机),n代表net(网络)s代表short(2字节),l代表long(4字节),INADDR_ANY指定地址让操作系统自己获取

例子:双方收发消息

  1. 服务器等待连接

  2. 客户端连接服务器

  3. 双方互发消息

  4. 注:可以多个客户端连接,但会出错,因为进程资源竞争(竞争的输入光标get();)

    可以优化为服务器作为中转来实现。例如:a发消息给b,服务器收到a消息转发给b

//客户端
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
int main(int argc,char **argv)
{
        if(argc != 3)
        {
                printf("parameter error\n");
                exit(-1);
        }
        int s_fd;
        int r_read;
        char msg[128];
        char read_buf[128];
        struct sockaddr_in s_addr;
        memset(&s_addr,0,sizeof(struct sockaddr_in));
​
        s_fd = socket(AF_INET,SOCK_STREAM,0);
        if(s_fd == -1)
        {
                perror("socket");
                exit(-1);
        }
        s_addr.sin_family = AF_INET;
        s_addr.sin_port = htons(atoi(argv[2]));
        inet_aton(argv[1],&s_addr.sin_addr);
        /*bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));*/
        //客户端不需要bind
        if(connect(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in)) == -1)
        {
                perror("connect");
                exit(-1);
        }
        while(1)
        {
                if(fork() == 0)
                {
                        while(1)
                        {
                                memset(&read_buf,0,sizeof(read_buf));
                                r_read = read(s_fd,read_buf,128);
                                printf("read:%d,buf:%s\n",r_read,read_buf);
                        }
                }
                while(1)
                {
                        memset(&msg,0,sizeof(msg));
                        printf("input: ");
                        gets(msg);
                        write(s_fd,msg,strlen(msg));
                }
        }
        close(s_fd);
        return 0;
}
​
//服务端
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
int main(int argc,char **argv)
{
        if(argc != 3)
        {
                printf("parameter error\n");
                exit(-1);
        }
        int s_fd;
        int x_fd;
        int r_read;
        char msg[128];
        char read_buf[128];
        struct sockaddr_in s_addr;
        struct sockaddr_in x_addr;
        memset(&s_addr,0,sizeof(struct sockaddr_in));
        memset(&x_addr,0,sizeof(struct sockaddr_in));
        s_fd = socket(AF_INET,SOCK_STREAM,0);
        if(s_fd == -1)
        {  
                perror("socket");
                exit(-1);
        }
        s_addr.sin_family = AF_INET;
        s_addr.sin_port = htons(atoi(argv[2]));
        inet_aton(argv[1],&s_addr.sin_addr);
        bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));
        listen(s_fd,10);
        int changdu = sizeof(struct sockaddr_in);
        while(1)
        {
                x_fd = accept(s_fd,(struct sockaddr *)&x_addr,&changdu);//这里必须要变量
                printf("client IP:%s\n",inet_ntoa(x_addr.sin_addr));
                if(fork() == 0)
                {
                        if(fork() == 0)
                        {
                                while(1)
                                {
                                        memset(&msg,0,sizeof(msg));
                                        printf("input: ");
                                        gets(msg);
                                        write(x_fd,msg,strlen(msg));
                                }
                        }
                        while(1)
                        {
                                memset(&read_buf,0,sizeof(read_buf));
                                r_read = read(x_fd,read_buf,128);
                                printf("read:%d,buf:%s\n",r_read,read_buf);
                        }
                }
        }
        close(x_fd);
        return 0;
}