Linux网络编程

  • 基础理论
    • 1、TCP/UDP/端口号
    • 2、字节序
  • 一、socket服务器与客户端的开发步骤
  • 二、具体使用步骤
    • 1.socket(创建连接协议)
    • 2.bind(地址准备好)
    • 3.listen(监听)
    • 4.accept(连接)
    • 5.read/write/send/recv(数据收发)
    • 6.connect
  • 三、例子
    • 1.服务端——固定IP地址连接
    • 2.客服端——固定IP地址连接
    • 2.服务端——自由指定地址
    • 2.客户端——自由指定地址
  • 总结

基础理论

1、TCP/UDP/端口号

管道、消息队列、共享内存、信号、信号量五种进程间通信属于单机通信。网络编程是由地址和数据组成的。地址是IP地址和端口号组成。数据传输需要遵循协议(HTTP、TCP、UDP)。通过端口号对客户端访问,有FTP、HTTP、SOCKET多种服务。
Linux的socket套接字所用协议最多的是TCP/UDP
TCP:面向连接(举例:A给B打电话,先拨号再接通);
UDP:面向报文(A给B发信息,不关心是否接通成功);
二者比较:TCP应用于数据传输要求精确的场景;UDP应用于大数据传输;
端口号作用:一台拥有IP地址的主机可以提供许多服务。比如:web、FTP、SMTP(电子邮件传输)服务;实际上,通过”IP地址+端口号“来区分不同服务。

举例:
服务器、TCP/UDP、IP地址、端口号的关系
我是xxx(服务器)
是说汉语(TCP/UDP)
我的楼号(IP地址)是xxxx
我的房间号(端口号)是xxxx
我在等着大家来访,敲门(监听)

客户端
获取服务器IP,再获取服务器端口号连接。

2、字节序

字节序是指多字节在计算机存储或者网络传输各字节的存储顺序。
little endian(小端字节序):将低序字节放在低地址(起始地址)。
Big endian(大端字节序): 将高序字节放在低地址(起始地址)。

举例:
假设需要传输的数据为0x01020304(32位)(前面为高序字节,后面为低序字节)
假设内存地址是 4000 & 4001 & 4002 & 4003
下表为低序 小端字节序

假设内存地址 二进制 十进制
4003 0000 0001 01
4002 0000 0010 02
4001 0000 0011 03
4000 0000 0100 04

下表为高序 大端字节序

假设内存地址 二进制 十进制
4003 0000 0100 04
4002 0000 0011 03
4001 0000 0010 02
4000 0000 0001 01

PS:X86序列CPU均为小端字节序;网络字节序均为大端字节序。

获取网络字节序和主机字节序

//头文件
#include <netinet/in.h>
//函数
uint16_t htons(uint16_t host16bitvalue);    //返回网络字节序的值
uint32_t htonl(uint32_t host32bitvalue);    //返回网络字节序的值
uint16_t ntohs(uint16_t net16bitvalue);     //返回主机字节序的值
uint32_t ntohl(uint32_t net32bitvalue);     //返回主机字节序的值
//h代表host,n代表net,s代表short(两个字节),l代表long(4个字节)。
//通过上面的4个函数可以实现主机字节序和网络字节序之间的转换。
//有时可以用INADDR_ANY,INADDR_ANY指定地址让操作系统自己获取.

提示:以下是本篇文章正文内容,下面案例可供参考

一、socket服务器与客户端的开发步骤

开发步骤:
1、创捷套接字。
2、为套接字添加信息(IP地址和端口号)。
3、监听网络连接。
4、监听到有客服端接入,接受一个连接。
5、数据交互。
6、关闭套接字,断开连接。

示意图:

二、具体使用步骤

1.socket(创建连接协议)

函数如下

//头文件
#include<sys/types.h>
#include<sys/socket.h>
//函数
int socket(int domain, int type, int protocol);
//返回
//success 返回新的套接字的文件描述符
//error 返回 -1

参数
domain:指向所使用的协议族,通常为AF_INET,表示互联网协议族(TCP/IP协议族)
AF_INET 代表 IPV4因特网域
AF_INET6 代表 IPV6因特网域
AF_UNIX 代表 UNIX域
AF_ROUTE 代表 路由套接字
AF_KEY 代表 密钥套接字
AF_UNSPEC 代表 未指定

type:指定socket类型
SOCK_STREAM 代表 TCP
SOCK_DGEAM 代表 UDP
SOCK_RAW 代表 IP与ICMP(对底层协议访问)

protocol:通常取为”0“,”0“对于与type类型的对应默认协议。
IPPROTO_TCP 代表 TCP协议
IPPROTO_UDP 代表 UDP协议
IPPROTO_SCIP 代表 SCIP协议
IPPROTO_TIPC 代表 TIPC协议

2.bind(地址准备好)

功能
用于绑定IP地址和端口号到socketfd。
函数如下

//头文件
#include<sys/types.h>
#include<sys/socket.h>
//函数
int bind(int sockfd, const struct sockaddr* addr, socklen_t addrlen);
//返回
//success 返回 0
//error 返回 -1

参数
sockfd: socket 返回的文件描述符
addr:struct sockaddr的地址,用于设定要绑定服务端的IP和端口号
addrlen:是addr结构的长度,可以设置成sizeof(struct sockaddr)。
其中:

struct sockaddr {sa_family_t sa_family;  //协议族char        sa_data[14];       //IP+端口号
}

上述结构体参数
sa_family 用于指定AF_***表示使用什么协议族的IP。
sa_data 存放IP和端口号。
直接向sa_data中写入IP和端口号有点麻烦,内核提供struct sockaddr_in结构体进行写入,通过**/usr/include/linux/in.h可以看到结构体原型。使用该结构体时需要包含<netinet/in.h>头文件**,且sockaddr_in结构体是专门为tcp/ip协议族使用。
同等替换为:

struct sockaddr_in{sa_family t   sin_family;//协议族in_port_t   sin_port;//端口号struct in_addr sin_addr;//IP地址结构体unsigned char sin_zero[8];//填充没有实际意义只是为跟sockadd结构在内存中对序这样两者才能相互转换
}

PS:寻找bind的优化结构步骤和命令
cd /user/include/
grep “struct sockaddr_in{” * -nir
vi linux/in.h +184
其中:n是行号 r是递归

bind步骤中需要用到地址转换API

//头文件
#include<arpa/inet.h>
//函数:把字符串形式的“192.168.1.123”转为网络能识别的格式 。
int inet_aton(const char* straddr,struct in_addr *addrp);
//函数:把网络格式的ip地址转为字符串形式。
char* inet_ntoa(struct in_addr inaddr);

3.listen(监听)

功能
设置能处理的最大连接数,listen()并未开始接受连线,只是设置sockect的listen模式,listen函数只用于服务器端,服务器进程不知道要与谁连接,因此,它不会主动地要求与某个进程连接,只是一直监听是否有其他客户进程与之连接,然后响应该连接请求,并对它做出处理,一个服务进程可以同时处理多个客户进程的连接。
主要就两个功能:将一个未连接的套接字转换为一个被动套接字(监听),规定内核为相应套接字排邦队的最大连接数。

//头文件
#include<sys/types.h>
#include<sys/socket.h>
//函数
int listen(int sockfd, int backlog);
//返回
//success 返回 0
//error 返回 -1

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

4.accept(连接)

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

函数如下

//头文件
#include<sys/types.h>
#include<sys/socket.h>
//函数
int accept(int sockfd, const struct sockaddr* addr, socklen_t addrlen);
//返回
//success 返回 接受的套接字的描述符
//error 返回 -1

参数
·sockfd:socket系统调用返回的服务器端socket描述符。
addr:用来返回已连接的对端(客户端)的协议地址。
addrled:客户端地址长度。
返回值:该函数的返回值是一个新的套接字描述符,返回值是表示已连接的套接字描述符。而第一个参数是服务器监听套接字描述符。一个服务器通常仅仅创建一个监听套接字,它在该服务器的生命周期内一直存在。

5.read/write/send/recv(数据收发)

在套接字通信中进行字节读取函数:read(),write()。与I/0中的读取函数略有区别,因为它们输入或输出的字节数处比可能比请求的少。

//头文件
#include <unistd.h>
//函数
ssize_t write(int fd,const void*buf,size_t nbytes);
ssize t read(int fd,void *buf,size_t nbyte);
//返回
//success 返回 均返回读或写的字节个教
//error 返回 -1

第一个函数将buf中的nbytes个字节写入到文件描述符fd中,成功时返回写的字节数。
第二个函数为从fd中读取nbyte个字节到buf中,返回实际所读的字节数。详细应用说明参考使用read write读写socket(套节字)。
网络I/o还有一些函数如:recv()/send(), readv()/writev(),recvmsg()/sendmsg(),recvfrom()/sendto()等。

常用第二套数据收发,在TCP套接字上发送数据函数:有连接

//头文件#include<sys/socket.h>
//函数
ssize_t send(int s,const void *msg,size_t len,int flags);
ssize_t recv(int s,void *buf,size_t len,int flags);
//返回
//success 返回 均返回读或写的字节个教
//error 返回 -1

send函数只能对处于连接状杰的套接字使用。
s为已建立好连接的套接字描述符,即accept函数的返回值。
msg指向存放待发送数据的缓冲区。
len为待发送数据的长度。
flags为控制选顶,一般设置为0。

recv函数包含3要素:套接字s,接收缓冲区buf,长度len
recv从参数所指定的套接字描述符(必须是面向连接的套接字)上接收数据并保存到参数buf所指定的缓冲区,参数len则为缓冲区长度,参数flags为控制选项,一般设置为0。

6.connect

功能
该函数用于绑定之后的客户端,即客户端与服务器建立连接。基本用法和bind一致。
函数如下

//头文件
#include<sys/types.h>
#include<sys/socket.h>
//函数
int connect(int sockfd, const struct sockaddr* addr, socklen_t addrlen);
//返回
//success 返回 0
//error 返回 -1

参数
sockfd: socket 返回的文件描述符
addr:struct sockaddr的地址,用于设定要绑定客户端的IP和端口号
addrlen:是addr结构的长度,可以设置成sizeof(struct sockaddr)。

小贴士:
Windows 的 cmd 连接 Linux
ping 172.20.10.3(主机地址) 地址连接
telnet 172.20.10.3 8989(主机地址) 连接Linux

三、例子

1.服务端——固定IP地址连接

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
//#include <linux/in.h>
#include <netinet/in.h>
#include <arpa/inet.h>//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)];
//};int main()
{int s_fd;int c_fd;char readBuf[128];char *msg="I get your connect";struct sockaddr_in s_addr;struct sockaddr_in c_addr;memset(&s_addr,0,sizeof(struct sockaddr_in));memset(&c_addr,0,sizeof(struct sockaddr_in));//1.sockets_fd = socket(AF_INET,SOCK_STREAM,0);if(s_fd == -1){perror("socket");exit(-1);}//2.binds_addr.sin_family = AF_INET;s_addr.sin_port = htons(8988);inet_aton("192.168.1.110",&s_addr.sin_addr);bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));//3.listenlisten(s_fd,10);//4.acceptint clen = sizeof(struct sockaddr_in);c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&clen);if(c_fd == -1){perror("accept");}printf("get connect:%s\n",inet_ntoa(c_addr.sin_addr));//5.readint n_read = read(c_fd,readBuf,128);if(n_read == -1){perror("read");}else{printf("get message:%d, %s\n",n_read,readBuf);}//6.writewrite(c_fd,msg,strlen(msg));return 0;
}

2.客服端——固定IP地址连接

include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
//#include <linux/in.h>
#include <netinet/in.h>
#include <arpa/inet.h>//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)];
//};int main()
{int c_fd;char readBuf[128];char *msg="msg from client";struct sockaddr_in c_addr;memset(&c_addr,0,sizeof(struct sockaddr_in));//1.socketc_fd = socket(AF_INET,SOCK_STREAM,0);if(c_fd == -1){perror("socket");exit(-1);}//2.connectc_addr.sin_family = AF_INET;c_addr.sin_port = htons(8988);inet_aton("192.168.1.110",&c_addr.sin_addr);if(connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr_in))){perror("connect");exit(-1);}//3.writewrite(c_fd,msg,strlen(msg));//4.readint n_read = read(c_fd,readBuf,128);if(n_read == -1){perror("read");}else{printf("get message:%d, %s\n",n_read,readBuf);}return 0;
}

2.服务端——自由指定地址

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
//#include <linux/in.h>
#include <netinet/in.h>
#include <arpa/inet.h>//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)];
//};int main(int argc, char **argv)//需要自己指定IP地址和端口号
{int s_fd;int c_fd;int mark=0;char readBuf[128];char msg[128]={0};//      char *msg="I get your connect";struct sockaddr_in s_addr;struct sockaddr_in c_addr;memset(&s_addr,0,sizeof(struct sockaddr_in));memset(&c_addr,0,sizeof(struct sockaddr_in));if(argc != 3){printf("param is error\n");exit(-1);}//1.sockets_fd = socket(AF_INET,SOCK_STREAM,0);if(s_fd == -1){perror("socket");exit(-1);}//2.binds_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));//3.listenlisten(s_fd,10);//4.acceptint clen = sizeof(struct sockaddr_in);while(1){c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&clen);if(c_fd == -1){perror("accept");}printf("get connect:%s\n",inet_ntoa(c_addr.sin_addr));mark++;//5.readif(fork() == 0){if(fork() == 0){while(1){sprintf(msg, "welcome NO.%d client",mark);write(c_fd,msg,strlen(msg));sleep(5);}}while(1){memset(readBuf,0,sizeof(readBuf));int n_read = read(c_fd,readBuf,128);if(n_read == -1){perror("read");}else{printf("get message from client:%d, %s\n",n_read,readBuf);}//6.write}break;}}return 0;
}

2.客户端——自由指定地址

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
//#include <linux/in.h>
#include <netinet/in.h>
#include <arpa/inet.h>//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)];
//};int main(int argc, char **argv)//需要自己输入地址
{int c_fd;int n_read;char readBuf[128];//      char *msg="msg from client";char msg[128]={0};struct sockaddr_in c_addr;memset(&c_addr,0,sizeof(struct sockaddr_in));if(argc != 3){printf("param is error\n");exit(-1);}//1.socketc_fd = socket(AF_INET,SOCK_STREAM,0);if(c_fd == -1){perror("socket");exit(-1);}//2.connectc_addr.sin_family = AF_INET;c_addr.sin_port = htons(atoi(argv[2]));inet_aton(argv[1],&c_addr.sin_addr);if(connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr_in)) ==-1){perror("connect");exit(-1);}//3.writewhile(1){if(fork() == 0){while(1){memset(msg,0,sizeof(msg));printf("input:");gets(msg);write(c_fd,msg,strlen(msg));}}//4.readwhile(1){memset(readBuf,0,sizeof(readBuf));n_read = read(c_fd,readBuf,128);if(n_read == -1){perror("read");}else{printf("get message from service:%d, %s\n",n_read,readBuf);}}}return 0;
}

总结

socket网络编程,总体步骤清晰。服务端所需要用到socket()、bind()、listen()、accept();客户端所需要用到socket()、connect();两者数据传输均需要read()、write()。
bind()中绑定IP地址和端口号,需要使用到内核指定结构体,需要理解接受;connect()和bind()使用方法相同。网络编程需要知道大端和小端字节序的转换,以及网络字节序和主机字节序的获取。
基于socket编程,可以深入进行FTP云盘项目代码编写。

Linux网络编程——socket、bind、listen、accpet、connect、read和write相关推荐

  1. linux网络编程二:基础socket, bind, listen, accept, connect

    linux网络编程二:基础socket, bind, listen, accept, connect 1. 创建socket #include <sys/types.h>     #inc ...

  2. Linux 网络编程——socket 网络编程

    文章目录 一.网络基础 TCP/UDP对比 TCP/IP协议族体系 socket IP地址 IP地址转化API inet_addr() inet_aton() inet_ntoa() inet_pto ...

  3. Linux网络编程,bind:error:Cannot assign requested address,Ubuntu网络桥接

    一:问题:刚开始学习Linux网络编程,第一次使用bind函数出现Cannot assign requested address,错误.在网上找了很多帖子但是都没有解决. 二: 问题一:也就是网上大部 ...

  4. Linux网络编程 | Socket编程(一):Socket的介绍、UDPSocket的封装、UDP服务器/客户端的实现

    目录 套接字编程 Sockaddr结构 字节序 地址转换 常用套接字接口 UDP的通信流程 UDPSocket的封装 UDP服务器 UDP客户端 套接字编程 所谓套接字(Socket),就是对网络中不 ...

  5. Linux网络编程(Socket)

    目录 网络编程(Socket)概述 引入 网络编程通识扫盲 socket套接字 套接字描述符 字节序 socket编程步骤 Linux提供的API简析 创建套接字即连接协议[socket](服.客) ...

  6. 27.Linux网络编程socket变成 tcp 高并发 线程池 udp

    好,咱们开始上课了,从今天开始咱们连续讲 8 天的,网络编程这个还是在linux环境下去讲,咱们先看一下咱们这 8 天都讲什么东西,跟大家一块来梳理一下,你先有个大概的印象,这些你也不要记,那么网络编 ...

  7. Linux网络编程——socket编程

    一.socket socket 网络套接字一个文件文件描述符指向一个套接字(该套接字内部由内核借助两个缓冲区实现(接收缓冲区和发送缓冲区))通讯过程中,套接字一定是 [成对] 出现的. 二.网络字节序 ...

  8. Linux 网络编程socket错误分析

    socket错误码: EINTR: 4 阻塞的操作被取消阻塞的调用打断.如设置了发送接收超时,就会遇到这种错误. 只能针对阻塞模式的socket.读,写阻塞的socket时,-1返回,错误号为INTR ...

  9. Linux网络编程 | Socket编程(二)TCPSocket的封装、TCP服务器多进程、多线程版本的实现

    目录 TCP的通信流程 TCPSocket的封装 TCP客户端 TCP服务器 多进程版本 多线程版本 TCP的通信流程 计算机网络 (三) 传输层 :一文搞懂UDP与TCP协议 在这篇博客中,我描述了 ...

最新文章

  1. 架构设计的真谛:系统与子系统、模块与组件、框架与架构
  2. 微软MSN推出新一代Live服务 能离线编辑博客
  3. python自学时间-Python 从入门到精通:一个月就够了!
  4. Linux下MySQL数据库的备份与还原,mysql快速导入导出数据库实例演示,解决mysql大数据量数据库导出慢的问题
  5. 学习:组件生命周期(1)
  6. python 结构数组_Python数组
  7. php js对话框,JavaScript_js弹出框、对话框、提示框、弹窗实现方法总结(推荐),一、JS的三种最常见的对话框- phpStudy...
  8. spark相关原理介绍
  9. bootstrap jasny fileinput插件冲突问题解决
  10. udp聊天?使用udp+python实现多人聊天室
  11. 换IP软件用户如何选择?
  12. arduino学习笔记-库函数解析_LiquidCrystal_i2c使用说明以及lcd1602的驱动
  13. 文件模式为 rw-r r linux,linux中-rw-rw-r-- l 是什么意思啊,linux 里命令ls -l 后,文件类型权...
  14. android,java知识点总结 (二)
  15. 【Python爬虫】IOS苹果商店指定APP评论爬取
  16. The bean sellergoods.FeignClientSpecification could not be registered. A bean with that name has a
  17. golang构建htpp服务
  18. 振荡次数计算机控制系统,计算机控制第四章.ppt
  19. 「基因组学」使用CAFE进行基因家族扩张收缩分析
  20. (最详细教程)中国知网caj格式论文如何转化为word,pdf,txt

热门文章

  1. linux open驱动失败,linux所遇到的问题记录
  2. LINUX常见服务列表
  3. Firefox常用扩展(extension)推荐
  4. 新零售全能商城多商户拼团砍价秒杀周期购分销论坛投票收银台点餐外卖小程序公众号
  5. Java中线程池拒绝策略——代码讲解
  6. carsim输入模块设置问题
  7. 利用 Web of science 寻找目标投稿期刊
  8. 模流分析的11个作用:让产品在设计过程中得到最优的方案
  9. 2022-2028全球及中国免下车洗车系统行业研究及十四五规划分析报告
  10. 鸿蒙智联 HarmonyOS Connect 设备首次发现过程