请选择 进入手机版 | 继续访问电脑版

[linux shell] 学习Linux网络编程基本函数

  [复制链接]
查看367 | 回复91 | 2021-9-12 15:57:45 | 显示全部楼层 |阅读模式
目次

1,创建套接字socket

函数原型:

  1. #include<sys/types.h>
  2. #include<sys/socket.h>
  3. int socket(int domain, int type, int protocol);
复制代码

参数列表:

domain参数有以下这些值

  1. AF_INET:IPv4协议
  2. AF_INET6:IPv6协议
  3. AF_LOCAL:Unix域协议
  4. AF_ROUTE:路由套接口
  5. AF_KEY:密钥套接口
复制代码

type的值:

  1. [code]SOCKET_STREAM:双向可靠数据流,对应TCPSOCKET_DGRAM:双向不可靠数据报,对应UDPSOCKET_RAW:提供传输层以下的协议,可以访问内部网络接口,例如接收和发送ICMP报文
复制代码
[/code]

protocol得值:

  1. type为SOCKET_RAW时需要设置此值说明协议类型,其他类型设置为0即可
复制代码

函数的作用是创建一个指定格式的套接字并返回其形貌 符,成功返回形貌 符,失败返回-1;

2,绑定套接字bind

函数原型:

  1. #include<sys/types.h>
  2. #include<sys/socket.h>
  3. int bind(int sockfd, const struct sockaddr *my_addr, socklen_t addrlen);
复制代码

参数列表:

  1. sockfd
复制代码
为之前创建的套接字形貌 符

  1. my_addr
复制代码
是一个通用套接字布局 体指针,在做tcp协议编程时通常利用
  1. sockaddr_in
复制代码
布局 体

该布局 体内容如下;

  1. struct socketaddr_in
  2. {
  3. unsigned short int sin_family;//对应地址族IP v4填AF_INTE
  4. uint16_t sin_port;//对应端口号
  5. struct in_addr sin_addr;//对应ip地址
  6. unsigned char sin_zero[8];
  7. };
  8. struct in_addr
  9. {
  10. uint32_t s_addr;
  11. };
复制代码

addrlen为该上述布局 体的大小,可以用sizeof求得;

在利用 bind函数前必要 先创建一个sockaddr_in范例 的布局 体,将服务器的信息保存到布局 体中,

然后将创建的套接字与之绑定;成功返回0,失败返回-1;

在设置端标语 和IP时先将布局 体清空,假如 是主函数传参,那么对应的端标语 和ip都是字符串格式,

必要 用函数转换,转换格式如下:

  1. char port[]="8888"
  2. char ip[]="192.168.1.1"
  3. struct sockaddr_in seraddr'
  4. seraddr.sin_port=htos(atoi(port))
  5. seraddr.sin_addr.s_addr=inet_addr(ip);
复制代码

3,创建监听;listen

函数原型:

  1. int listen(int fd, int backlog);
复制代码

参数列表:

fd为要监听的套接字形貌 符;backlog为监听队列的大小;

(1) 实行 listen 之后套接字进入被动模式。

(2) 队列满了以后,将拒绝新的毗连 哀求 。客户端将出现毗连 D 错误WSAECONNREFUSED。

(3) 在正在listen的套接字上实行 listen不起作用。

4,等待毗连 accept

函数原型:

  1. #include <sys/socket.h>
  2. int accept(int s, struct sockaddr * addr, int * addrlen);
复制代码

对比bind函数可以发现两者的参数几乎一样,但是accept中的addr不被const修饰,

也就是说addr是用来保存毗连 的客户端的地址信息的,同杨addlen时返回的addr的大小;

以是 accept函数的作用就是返回已毗连 的客户端的文件形貌 符,

并将客户端的地址信息保存在一个新的sockaddr_in布局 体中;链接失败返回-1;

5, 收发消息send和recv

函数原型:

  1. int send( SOCKET s, const char FAR *buf, int len, int flags );
  2. int recv( SOCKET s, char FAR *buf, int len, int flags);
复制代码

该函数的参数:

  • 第一个参数指定发送/担当 端套接字形貌 符;
  • 第二个参数指明一个存放应用程序要发送数据的缓冲区;
  • 第三个参数指明实际 要发送/吸收 的数据的字节数;
  • 第四个参数一样平常 置0。

send的流程:

这里只形貌 同步Socket的send函数的实行 流程。

当调用该函数时,send先比较待发送数据的长度len和套接字s的发送缓冲的长度,

  •  假如 len大于s的发送缓冲区的长度,该函数返回SOCKET_ERROR;
  • 假如 len小于或者等于s的发送缓冲区的长度,那么send先检查协议是否正在发送s的发送缓冲中的数据,
  • 假如 是就等待协议把数据发送完,
  • 假如 协议还没有开始发送s的发送缓冲中的数据或者s的发送缓冲中没有数据,那么send就比较s的发送缓冲区的剩余空间和len,
  • 假如 len大于剩余空间大小send就不停 等待协议把s的发送缓冲中的数据发送完,
  • 假如 len小于剩余空间大小send就仅仅把buf中的数据copy到剩余空间里(留意 并不是send把s的发送缓冲中的数据传到毗连 的另一端的,而是协议的,send仅仅是把buf中的数据copy到s的发送缓冲区的剩余空间里);
  • 假如 send函数copy数据成功,就返回实际 copy的字节数,
  • 假如 send在copy数据时出现错误,那么send就返回SOCKET_ERROR;
  • 假如 send在等待协议传送数据时网络断开的话,那么send函数也返回SOCKET_ERROR。

要留意 send函数把buf中的数据成功copy到s的发送缓冲的剩余空间里后它就返回了,但是此时这些数据并不肯定 立即 被传到毗连 的另一端。

  • 假如 协议在后续的传送过程中出现网络错误的话,那么下一个Socket函数就会返回SOCKET_ERROR。
  • (每一个除send外的Socket函数在实行 的最开始总要先等待套接字的发送缓冲中的数据被协议传送完毕才能继续,
  • 假如 在等待时出现网络错误,那么该Socket函数就返回SOCKET_ERROR)。

recv的流程:

这里只形貌 同步Socket的recv函数的实行 流程。

当应用程序调用recv函数时,recv先等待s的发送缓冲中的数据被协议传送完毕,

  • 假如 协议在传送s的发送缓冲中的数据时出现网络错误,那么recv函数返回SOCKET_ERROR,
  • 假如 s的发送缓冲中没有数据或者数据被协议成功发送完毕后,recv先检查套接字s的吸收 缓冲区,
  • 假如 s吸收 缓冲区中没有数据或者协议正在吸收 数据,那么recv就不停 等待,只到协议把数据吸收 完毕。
  • 当协议把数据吸收 完毕,recv函数就把s的吸收 缓冲中的数据copy到buf中

(留意 协议吸收 到的数据大概 大于buf的长度,以是 在这种环境 下要调用几次recv函数才能把s的吸收 缓冲中的数据copy完。

recv函数仅仅是copy数据,真正的吸收 数据是协议来完成的),recv函数返回着实 际copy的字节数。

  • 假如 recv在copy时出错,那么它返回SOCKET_ERROR;
  • 假如 recv函数在等待协议吸收 数据时网络制止 了,那么它返回0。
  • tcp协议本身是可靠的,并不等于应用程序用tcp发送数据就肯定 是可靠的.
  • 不管是否壅闭 ,send发送的大小,并不代表对端recv到多少的数据.
  • 在壅闭 模式下, send函数的过程是将应用程序哀求 发送的数据拷贝到发送缓存中发送并得到确认后再返回.

但由于发送缓存的存在,表现为:假如 发送缓存大小比哀求 发送的大小要大,那么send函数立即 返回,同时向网络中发送数据;

否则,send向网络发送缓存中不能容纳的那部分数据,并等待对端确认后再返回(吸收 端只要将数据收到吸收 缓存中,

就会确认,并不肯定 要等待应用程序调用recv);

  • 在非壅闭 模式下,send函数的过程仅仅是将数据拷贝到协议栈的缓存区而已,
  • 假如 缓存区可用空间不够,则尽本领 的拷贝,
  • 返回成功拷贝的大小;如缓存区可用空间为0,则返回-1,同时设置errno为EAGAIN.

5,关闭套接字形貌 符close

函数:

  1. close(sockfd);
复制代码

和文件操作一样,套接字也是一个文件,利用 完之后要关闭;

6,基于tcp协议的C/S服务器模子

Linux学习笔记-网络编程(二)

图解tcp模子

7,实当代 码

服务端:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <strings.h>
  4. #include <sys/types.h>
  5. #include <sys/socket.h>
  6. #include <netinet/in.h>
  7. #include <netinet/ip.h>
  8. #include <arpa/inet.h>
  9. #include <unistd.h>
  10. typedef struct sockaddr_in SIN;
  11. typedef struct sockaddr SA;
  12. int main(int argc,char *argv[])
  13. {
  14. SIN seraddr;
  15. SIN cliaddr;
  16. int len=sizeof(SIN);
  17. //创建监听套接字
  18. int lisfd=socket(AF_INET,SOCK_STREAM,0);
  19. if(lisfd<0)
  20. {
  21. perror("socket");
  22. exit(0);
  23. }
  24. printf("创建套接字%d成功\n",lisfd);
  25. bzero(&seraddr,sizeof(seraddr));
  26. seraddr.sin_family=AF_INET;
  27. seraddr.sin_port=htons(8888);
  28. seraddr.sin_addr.s_addr=inet_addr("192.168.1.6");
  29. //绑定套接子
  30. int ret=bind(lisfd,(SA*)(&seraddr),len);
  31. if(ret<0)
  32. {
  33. perror("bind");
  34. exit(0);
  35. }
  36. printf("绑定成功\n");
  37. //开始监听
  38. ret=listen(lisfd,1024);
  39. if(ret<0)
  40. {
  41. perror("listen");
  42. exit(0);
  43. }
  44. printf("监听成功\n");
  45. //等待连接,将连接的套接字信息保存
  46. int clifd=accept(lisfd,(SA*)(&cliaddr),(socklen_t *)(&len));
  47. if(clifd<0)
  48. {
  49. perror("accept");
  50. exit(0);
  51. }
  52. printf("客户端%d连接成功\n",clifd);
  53. //读写
  54. char readbuf[1024]={0};
  55. char sendbuf[1024]={0};
  56. while(1)
  57. {
  58. recv(clifd,readbuf,sizeof(readbuf),0);
  59. printf("recv:%s\n",readbuf);
  60. fgets(sendbuf,sizeof(sendbuf),stdin);
  61. send(clifd,sendbuf,sizeof(sendbuf),0);
  62. }
  63. //关闭套接字
  64. close(clifd);
  65. close(lisfd);
  66. return 0;
  67. }
复制代码

客户端:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <strings.h>
  4. #include <sys/types.h>
  5. #include <sys/socket.h>
  6. #include <netinet/in.h>
  7. #include <netinet/ip.h>
  8. #include <arpa/inet.h>
  9. #include <unistd.h>
  10. typedef struct sockaddr_in SIN;
  11. typedef struct sockaddr SA;
  12. int main(int argc,char *argv[])
  13. {
  14. SIN seraddr;
  15. //创建监听套接字
  16. int serfd=socket(AF_INET,SOCK_STREAM,0);
  17. if(serfd<0)
  18. {
  19. perror("socket");
  20. exit(0);
  21. }
  22. printf("创建套接字%d成功\n",serfd);
  23. bzero(&seraddr,sizeof(seraddr));
  24. seraddr.sin_family=AF_INET;
  25. seraddr.sin_port=htons(8888);
  26. seraddr.sin_addr.s_addr=inet_addr("192.168.1.6");
  27. //请求连接
  28. int ret=connect(serfd,(SA*)(&seraddr),sizeof(SIN));
  29. if(ret==-1)
  30. {
  31. perror("connect");
  32. exit(0);
  33. }
  34. printf("连接成功\n");
  35. //读写
  36. char senbuf[1024]={0};
  37. char readbuf[1024]={0};
  38. while(1)
  39. {
  40. fgets(senbuf,sizeof(senbuf),stdin);
  41. send(serfd,senbuf,sizeof(senbuf),0);
  42. recv(serfd,readbuf,sizeof(readbuf),0);
  43. printf("recv:%s\n",readbuf);
  44. }
  45. //关闭套接字
  46. close(serfd);
  47. return 0;
  48. }
复制代码

以上就是学习Linux网络编程基本函数的详细 内容,更多关于Linux网络编程基本函数的资料请关注脚本之家别的 干系 文章!


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

论坛的人气不行了!
回复

使用道具 举报

avatar WY20172017 | 2021-9-14 17:30:19 | 显示全部楼层
admin楼主,我告诉你一个你不知道的的秘密,有一个牛逼的网站,运动刷步数还是免费刷的,QQ和微信都可以刷,特别好用。访问地址:http://yd.mxswl.com 猫先森网络
回复

使用道具 举报

avatar 荷叶224 | 2021-9-15 07:54:08 | 显示全部楼层
最近精神病院在打折,admin楼主去看看吧?
回复

使用道具 举报

avatar 玉米人 | 2021-9-17 05:43:36 | 显示全部楼层
终于看完了,很不错!
回复

使用道具 举报

avatar 易网随缘倚 | 2021-9-18 08:08:15 | 显示全部楼层
admin楼主,替我问候您主治大夫!
回复

使用道具 举报

avatar 飞儿506 | 2021-9-19 12:24:34 | 显示全部楼层
今天的心情很不错啊
回复

使用道具 举报

avatar 邱建华 | 2021-9-26 21:34:37 | 显示全部楼层
有品位!
回复

使用道具 举报

avatar 执着等待等wc | 2021-9-29 19:35:58 | 显示全部楼层
刚分手,心情不好!
回复

使用道具 举报

avatar 喜喜保镖撼 | 2021-9-30 05:48:08 | 显示全部楼层
admin楼主,我告诉你一个你不知道的的秘密,有一个牛逼的网站,影视频道的网站所有电影和连续剧都可以免费看的。访问地址:http://tv.mxswl.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则