• socket开发步骤及相关API介绍


    socket服务器和客户端的开发步骤

    TCP服务端:

    1. 创建套接字socket
    2. 为套接字添加信息(IP地址和端口号)bind
    3. 监听网络连接listen
    4. 监听到由客户端接入,接受一个连接accept
    5. 数据交互read、write
    6. 关闭套接字,断开连接close

    TCP客户端:

    1. 创建套接字socket
    2. 知道IP地址端口号与服务端连接connect
    3. 数据交互read、write
    4. 关闭套接字,断开连接close

    创建套接字socket

    函数原型:

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

    参数:

    1.domain:指明所使用的协议,通常为AF_INEF,表示互联网协议族(TCP/IP协议族)

    • AF_INET --- IPv4因特网域
    • AF_INET6 --- IPv6因特网域
    •  AF_UNIX --- Unix域
    • AF_ROUTE --- 路由套接字
    • AF_KEY --- 密钥套接字
    • AF_UNSPEC --- 未指定

    2.type:指定socket的类型

    • SOCK_STREAM:流式套接字,面向连接的通信流,它使用TCP协议,从而保证了数据传输的正确性和顺序性。
    • SOCK_DGRAM:数据报套接字定义了一种无连接的服务,数据通过相互独立的报文进行传输,是无序的,并且不保证是可靠、无差错的。它使用数据协议UDP。
    • SOCK_RAM:允许程序使用低层协议,原始套接字允许对底层协议如IP或ICMP进行直接访问,功能强大但使用较为不便,主要用于一些协议的开发。

    3.protocol:通常赋值为0

    • 0选择type类型对应的默认协议
    • IPPROTO_TCP --- TCP传输协议
    • IPPROTO_UDP --- UDP传输协议
    • IPPROTO_SCTP --- SCTP传输协议
    • IPPROTO_TIPC --- TIPC传输协议

    返回值:

    成功返回socket套接字描述符,失败返回-1

    套接字添加信息bind

    用于绑定IP地址和端口号到socketfd

    函数原型:

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

    参数:

    1. int sockfd:socket描述符
    2. const struct sockaddr *addr:是一个执行包含有本机IP地址及端口号等信息的socket类型的指针,指向要绑定给sockfd的协议地址结构,这个地址结构根据地址创建socket时的地址协议族的不同而不同。
    3. socklen_t addrlen:第二个参数结构体的长度

    man手册给的第二个参数是:

    但是一般写成如下形式,再强转为struct sockaddr *形式

    例如如下写法:

    监听网络连接listen

    listen()的功能:

    • 设置能处理的最大连接数,listen()并未开始接受连线,只是设置socket的listen模式,listen函数只用于服务器端,服务器进程不知道要与谁连接,因此它不会主动的要求与某个进程连接,只是一直监听是否有其他客户进程与之链接,然后响应该连接请求,并对它做出处理,一个服务进程可以同时处理多个客户进程的连接。主要就两个功能:将一个未连接的套接字转换未一个被动套接字(监听),规定内核为套接字排队的最大连接数。
    • 内核为任何一个给监听套接字维护两个队列
    1. 未完成连接队列,每个这样的SYN报文段对应其中一项:已由某个客户端发出并到达服务器,而服务器正在等待完成响应的TCP三次握手过程,这些套接字处于SYN_REVD状态。
    2. 已完成连接队列。每个已完成TCP三次握手过程的客户端对应其中一项,这些套接字处于ESTABLISHED状态。

    函数原型:

     int listen(int sockfd, int backlog);

    参数:

    1. int sockfd:是socket系统调用返回的服务器端socket描述符
    2. int backlog:指定在请求队列中允许的最大请求数

    返回值:

    成功返回0,失败返回-1,并且errno中包含相应的错误码

    客户端连接服务器connect

    功能:

    用于绑定之后的client端,与服务器建立连接

    函数原型:

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

    参数:

    1. int sockfd:socket系统调用返回的服务器端socket描述符
    2. struct sockaddr *addr:用来返回已连接的对端(客户端)的协议地址
    3. socklen_t *addrlen:客户端地址的长度

    返回

    成功返回0,失败返回-1,并且errno中包含相应的错误码

    接受连接accept

    功能:

    accept函数由TCP服务器调用,用于从已经完成连接队列队头返回下一个已完成连接,如果已完成连接队列为空,那么进程之间进入睡眠。

    函数原型:

    int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

    参数:

    1. int sockfd:socket系统调用返回的服务器端socket描述符
    2. struct sockaddr *addr:用来返回已连接的对端(客户端)的协议地址
    3. socklen_t *addrlen:客户端地址的长度

    返回值:

    该函数的返回值是一个新的套接字描述符,返回值是表示已连接的套接字描述符,而第一个参数是服务器监听套接字描述都,一个服务器通常仅仅创建一个监听套接字,它在服务器的生命周期内一直存在。内核为每个由服务器进程接受的客户端连接创建一个已连接套接字(表示TCP三次握手协议已完成),当服务器完成对某个给定客户的服务时,响应的已连接套接字就会被关闭。

    数据交互read、write

    与文件编程中使用的read、write是一模一样的,不过多赘述

    此外还要另外两种数据收发API:

    1.  ssize_t send(int sockfd, const void *buf, size_t len, int flags);
    2. ssize_t recv(int sockfd, void *buf, size_t len, int flags);

    其实和read、write也是差不多的,只不过多了一个flag参数,flag表示控制选项,一般设置为0。

    字节序转换API

           #include

           uint32_t htonl(uint32_t hostlong);返回网络字节序的值

           uint16_t htons(uint16_t hostshort);返回网络字节序的值

           uint32_t ntohl(uint32_t netlong);返回主机字节序的值

           uint16_t ntohs(uint16_t netshort);返回主机字节序的值uint32_t

    h代表host,n代表net,s代表short(两个字节),l代表long(四个字节),通过上面4个函数可以表示主机字节序和网络字节序之间的转换。有时可以用INADDR_ANY , INADDR_ANY指定地址让操作系统自己获取。

    地址转换API

    一般用下面黑体标出的两个

            #include
           #include
           #include

           int inet_aton(const char *cp, struct in_addr *inp);把字符串形式的192.168.1.123转为网络能识别的格式

           in_addr_t inet_addr(const char *cp);

           in_addr_t inet_network(const char *cp);

           char *inet_ntoa(struct in_addr in);把网络格式的ip地址转为字符串形式

           struct in_addr inet_makeaddr(int net, int host);

           in_addr_t inet_lnaof(struct in_addr in);

           in_addr_t inet_netof(struct in_addr in);

    示例一:

    服务端:连接客户端并读取客户端IP、发送的信息并返回读取状态。

    1. #include
    2. #include
    3. #include
    4. //#include
    5. #include
    6. #include
    7. #include
    8. #include
    9. int main()
    10. {
    11. int s_fd;
    12. char readBuf[128];
    13. memset(readBuf,0,sizeof(readBuf));
    14. int nread=0;
    15. struct sockaddr_in s_addr;
    16. struct sockaddr_in c_addr;
    17. memset(&s_addr,0,sizeof(struct aockaddr_in *));
    18. memset(&s_addr,0,sizeof(struct aockaddr_in *));
    19. s_fd=socket(AF_INET,SOCK_STREAM,0);
    20. if(s_fd==-1)
    21. {
    22. printf("creat soclet failed\n");
    23. perror("socket");
    24. exit(-1);
    25. }
    26. s_addr.sin_family=AF_INET;
    27. s_addr.sin_port=htons(9090);
    28. inet_aton("169.254.6.127",&(s_addr.sin_addr));
    29. bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));
    30. listen(s_fd,10);
    31. int clen=sizeof(struct sockaddr_in);
    32. int c_fd=accept(s_fd,(struct sockaddr *)&c_addr,&clen);
    33. if(c_fd == -1)
    34. {
    35. perror("acccept");
    36. }
    37. printf("get connect :%s\n",inet_ntoa(c_addr.sin_addr));
    38. nread=read(c_fd,readBuf,128);
    39. if(nread ==-1)
    40. {
    41. perror("read");
    42. }
    43. else if(nread>0)
    44. {
    45. printf("get message:%d,%s\n",nread,readBuf);
    46. }
    47. else
    48. {
    49. printf("client quit\n");
    50. }
    51. write(c_fd,"hhhhhhhhhhhhhhh",128);
    52. return 0;
    53. }

    示例二:

    客户端:

    1. #include
    2. #include
    3. #include
    4. //#include
    5. #include
    6. #include
    7. #include
    8. #include
    9. int main()
    10. {
    11. int c_fd;
    12. char readBuf[128];
    13. memset(readBuf,0,sizeof(readBuf));
    14. int nread=0;
    15. struct sockaddr_in c_addr;
    16. memset(&c_addr,0,sizeof(struct aockaddr_in *));
    17. c_fd=socket(AF_INET,SOCK_STREAM,0);
    18. if(c_fd==-1)
    19. {
    20. printf("creat soclet failed\n");
    21. perror("socket");
    22. exit(-1);
    23. }
    24. c_addr.sin_family=AF_INET;
    25. c_addr.sin_port=htons(9090);
    26. inet_aton("169.254.6.127",&(c_addr.sin_addr));
    27. if(connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr)) ==-1)
    28. {
    29. perror("connect");
    30. exit(-1);
    31. }
    32. write(c_fd,"xxxxxxxxx",128);
    33. nread=read(c_fd,readBuf,128);
    34. if(nread ==-1)
    35. {
    36. perror("read");
    37. }
    38. else
    39. {
    40. printf("get message from sever:%d,%s\n",nread,readBuf);
    41. }
    42. return 0;
    43. }

  • 相关阅读:
    WEB应用程序编程接口API
    浏览器事件循环原理 —— 任务优先级
    Python的基础语法(十五)
    多任务环境中如何喂看门狗?
    备战数学建模42-缺失值和异常值的处理方法(攻坚战6)
    Linux OOM killer
    2022 云原生编程挑战赛圆满收官,见证冠军战队的诞生
    Spring进阶(二):AOP
    java毕业设计房屋中介网络平台Mybatis+系统+数据库+调试部署
    青鸟新生攻略 | 先收好这篇入学防诈骗指南
  • 原文地址:https://blog.csdn.net/m0_58985552/article/details/134189865