linux网络编程百度云,[LINUX-07]linux网络编程(完整版)

之间在网上看到很多网络编程都是一个一个demo,今天我把之前学到的汇总起来,希望大家可以进行补充。

我理解的网络通信分为4种

1,udp客户端

2,udp服务端

3,tcp客户端

4,tcp服务端

线程中我使用过两种方式编程,一种是经典函数式编程加上标志位,如下:

while(1)

{

server_init();

client_init();

sock_send();

select_handler();

}

其中各函数里面放置了大量的标志位,如下:

void client_init(void)

{//确认客户端初始化标志位//}void sock_send(void)

{//判断客户端标志位,成功则继续进行

if(client_init_flag)

{//发送操作//确认客户端发送标志位

}

}void select_handler(void)

{if(send_flag)

{//处理数据并接受可以用select

}

}

这种方式,我觉得在看代码的时候很乱,但是他在大量的通信时还比较友好,可以建立一个结构体数组,每个数组成员代表一个客户端,结构体放置client_init_flag和send_flag。

还有一种方式采用的是状态机编程

创建枚举

typedef enumclient_statues_t

{

init_flag_status,

send_flag_status,

}client_statues_t;

client_statues_t client_statues;while(1)

{//先接受,后发送

switch(client_statues)

{caseinit_flag_status:

client_init();break;casesend_flag_status:

sock_send();break;

。。。

}

}

状态机在单片机使用很常见,但是如果多客户端初始化与发送,容易搞混,并且个人觉得增删查改略费劲,有可能是我自己水平有限,所以今天只写了一个关于第一种方式的代码。因为标志位太多了,而且各种判断比较乱,所以以下就没有各种标志位,但真正项目中是要有的并且还需要有打印日志功能(printf函数),整体思路如下:

>>创建udp服务端,创建tcp服务端>>创建udp客户端,创建tcp客户端>>发送数据>>接受数据并处理

首先是udp服务端,创建tcp服务端,服务端程序比客户端较简单

//返回值为是否成功标志,需要在各行赋值代码中判断,此代码不进行演示//create_udpServer()、create_tcpServer()参数可以为全局变量的关于服务器端的结构体,结构体里端口号,初始化标志位,等等,此代码不进行演示

structsockaddr_in udp_sockServer;void create_udpServer(void)

{

udp_socket= socket(AF_INET, SOCK_DGRAM,0);//INADDR_ANY,

udp_sockServer.sin_addr.s_addr =htonl(INADDR_ANY);

udp_sockServer.sin_port= htons(udp_port);//port自己设置

udp_sockServer.sin_family =AF_INET;

bind(udp_socket, (struct sockaddr *)&udp_sockServer, sizeof(structsockaddr_in));

}structsockaddr_in tcp_sockServer;void create_tcpServer(void)

{

tcp_socket= socket(AF_INET, SOCK_STREAM, 0);

tcp_sockServer.sin_addr.s_addr=htonl(INADDR_ANY);

tcp_sockServer.sin_port= htons(tcp_podt);//port自己设置

tcp_sockServer.sin_family =AF_INET;

bind(tcp_socket, (struct sockaddr *)&tcp_sockServer, sizeof(structsockaddr_in));

listen(tcp_socket, n);//n自己设置

}void server_init(void)

{

create_udpServer();

create_tcpServer();

}

其次是创建tcp和udp的客户端

//返回值为是否成功标志,需要在各行赋值代码中判断,此代码不进行演示//create_tcpClient()、create_udpClient(v)参数可以为全局变量的关于客户端的结构体,要连接服务器的结构体信息,初始化标志位,等等,此代码不进行演示

structsockaddr_in tcpServer;void create_tcpClient(void)

{

tcpSock= socket(AF_INET, SOCK_STREAM, 0);//客户端需要知道服务端信息

tcpServer.sin_addr.s_addr = htonl(ip);//ip自己设置

tcpServer.sin_port = htons(tcpPort);//port自己设置

tcpServer.sin_family =AF_INET;/*设置setsockopt参数 ,具体请看我之间发的一篇blog

*https://blog.csdn.net/qq_32166779/article/details/88853435

*/}/*把connect单独写是因为这个步骤比较特殊,他是阻塞函数,需要有一定的延时,有两种方、法,一种是利用setsockopt:https://blog.csdn.net/qq_32166779/article/details/88853435一种是利用select检查socket描述符:http://blog.csdn.net/ast_224/article/details/2957294

*/

void tcpClient_connectServer(void)

{//这个tcpsock和create_tcpClient函数中是同一个

connect(tcpSock, (struct sockaddr *)&tcpServer, sizeof(structsockaddr_in));

}structsockaddr_in udpServer;void create_udpClient(void)

{

udpSock= socket(AF_INET, SOCK_DGRAM, 0);

udpServer.sin_addr.s_addr= htonl(pUDP->ip);

udpServer.sin_port= htons(pUDP->udpPort);

udpServer.sin_family=AF_INET;

}void client_init(void)

{

create_tcpClient();

tcpClient_connectServer();

create_udpClient();

}

udp 服务器接受与发送函数,这个只设置能接受一个客户端发数

//udp先接受客户端的数据,然后发送数据

void udp_server_recviveandsend(void)

{/*参数udp_socket为 建立udp服务端的*/recvfrom(udp_socket, rxBuf, rxbuf_len,0,(struct sockaddr *)&sockClient, &(sizeof(structsockaddr_in)));

sendto(udp_socket , txBuf, txbuf_len,0, (struct sockaddr *)&sockClient,sizeof(structsockaddr_in));

}//tcp客户端发数与接受

void udp_server_recviveandsend(void)

{/*tcpSock为建立*/send(tcpSock , txbuf, len,0);

recv(tcpSock , rxbuf, len,0);

}//tcp服务端是最难的,需要考虑客户端的ip,个数限制,并根据每个客户端进行通信,这里需要设置一个结构体数组,

typedefstructtcp_accept_t

{int lifeNum;//用来设置socket存在时间

int socket;//ulong ip; //保存客户端ip

ushort port;//保存客户端端口号

intlen;

}tcp_accept_t;#define num 100//定义最大接受客户端的数量,tcp_accept_t tcp_accept[num];

tcp接受客户端大体思路是这样想的:

1,利用select先获取accept之前的套接字

2,当accept响应,建立新套接字

3,有了新套接字,利用select获取receive的响应

4,如果新来客户端总数超过num,则放弃最早的客户端

create_tcpServer();structsockaddr_in sockClient;while(1)

{/*先*/

int socketMax=-1;

fd_set fdSockSet;intfd_act;structtimeval timeout;

FD_ZERO(&fdSockSet);//tcp_sockServer与create_tcpServer()一致

if(tcp_sockServer>0)

{

FD_SET(tcp_sockServer,&fdSockSet);if(socketMax < tcp_sockServer) {socketMax =tcp_sockServer};

}for(int i = 0; i

{if(tcp_accept[i].socket>0)

{

FD_SET(tcp_accept[i].socket,&fdSockSet);if(socketMax

}

}if(socketMax > 0){

timeout.tv_sec= 5;

timeout.tv_usec= 0;

fd_act= 0;

fd_act= select(socketMax+1, &fdSockSet, NULL, NULL, &timeout);if(fd_act>0)

{for(int i = 0; i

{if(tcp_accept[i].socket>0)

{

FD_SET(tcp_accept[i].socket,&fdSockSet);if(FD_ISSET(tcp_accept[i].socket, &fdSockSet))

{

recv(tcp_accept[i].socket, rxbuf, SOCKET_TCP_RECV,0);

}

}

}if(FD_ISSET(tcp_sockServer, &fdSockSet))

{

newSocket= -1;

newSocket= accept(tcp_sockServer, (struct sockaddr *)&sockClient, (socklen_t *)&addrlen); //sockclient为连接的客户端信息,addrlen为sockaddr结构体长度。 if(newSocket>0){

ip = ntohl(pTCP->sockClient.sin_addr.s_addr);

port= ntohs(pTCP->sockClient.sin_port);

sLinger.l_onoff= 0;

ret= setsockopt(newSocket, SOL_SOCKET, SO_LINGER, &sLinger, sizeof(structlinger));

lifeNumMax++;if(lifeNumMax >= 100000000){

lifeNumMax= 1;for(i=0;i 0){

tcpAccept[i].lifeNum-= 100000000;

}

}

}/*IP相同,则不需要关闭任何客户端*/

for (i = 0; i < SOCKET_ACCEPT_MAX; i++) {if (tcpAccept[i].socket > 0 && tcpAccept[i].ip ==ip) {

j=i;gotoaccept_new_socket;

}

}/*新来设备,判断是否num不够,如果num够则新增acceptsocket*/

for (i = 0; i < SOCKET_ACCEPT_MAX; i++) {if (tcpAccept[i].socket==0) {

j=i;gotoaccept_new_socket;

}

}/*新来设备,判断是否num不够,如果num不够则新增acceptsocket并放弃最早的客户端*/j= 0;

lifeNumMin= tcpAccept[0].lifeNum;for (i = 1; i < SOCKET_ACCEPT_MAX; i++) {if(lifeNumMin >tcpAccept[i].lifeNum){

lifeNumMin=tcpAccept[i].lifeNum;

j=i;

}

}

accept_new_socket:if(tcpAccept[j].socket > 0){

close(tcpAccept[j].socket);

}

tcpAccept[j].socket=newSocket;

tcpAccept[j].ip=ip;

tcpAccept[j].port=port;

tcpAccept[j].status= 0xff; /*socket正常使用*/tcpAccept[j].lifeNum=lifeNumMax;

}

}

}

其中放弃最早的客户端采用了比较简单的算法

每个客户端在连接时给予一个lifeNum生命值,还有一个不断增加的计数器 lifeNumMax,当客户端增加到最大数量时,比较前几个客户端的生命值,把最小的除去,因为它连接的最久。生命值代码为

lifeNumMax++;if(lifeNumMax >= 100000000){

lifeNumMax= 1;for(i=0;i 0){

tcpAccept[i].lifeNum-= 100000000;

}

}

}

原文链接:https://blog.csdn.net/qq_32166779/article/details/88861648

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
教程非常不错,价值280元,绝对是干货 Linux网络编程(总共41集) 讲解Linux网络编程知识,分以下四个篇章。 Linux网络编程之TCP/IP基础篇 Linux网络编程之socket编程篇 Linux网络编程之进程间通信篇 Linux网络编程之线程篇 Linux网络编程之TCP/IP基础篇 01TCPIP基础(一) ISO/OSI参考模型 TCP/IP四层模型 基本概念(对等通信、封装、分用、端口) 02TCPIP基础(二) 最大传输单元(MTU)/路径MTU 以太网帧格式 IC MP ARP RARP 03TCPIP基础(三) IP数据报格式 网际校验和 路由 04TCPIP基础(四) TCP特点 TCP报文格式 连接建立三次握手 连接终止四次握手 TCP如何保证可靠性 05TCPIP基础(五) 滑动窗口协议 UDP特点 UDP报文格式 Linux网络编程之socket编程篇 06socket编程(一) 什么是socket IPv4套接口地址结构 网络字节序 字节序转换函数 地址转换函数 套接字类型 07socket编程(二) TCP客户/服务器模型 回射客户/服务器 socket、bind、listen、accept、connect 08socket编程(三) SO_REUSEADDR 处理多客户连接(process-per-conection) 点对点聊天程序实现 09socket编程(四) 流协议与粘包 粘包产生的原因 粘包处理方案 readn writen 回射客户/服务器 10socket编程(五) read、write与recv、send readline实现 用readline实现回射客户/服务器 getsockname、getpeername gethostname、gethostbyname、gethostbyaddr 11socket编程(六) TCP回射客户/服务器 TCP是个流协议 僵进程与SIGCHLD信号 12socket编程(七) TCP 11种状态 连接建立三次握手、连接终止四次握手 TIME_WAIT与SO_REUSEADDR SIGPIPE 13socket编程(八) 五种I/O模型 select 用select改进回射客户端程序 14socket编程(九) select 读、写、异常事件发生条件 用select改进回射服务器程序。 15socket编程(十) 用select改进第八章点对点聊天程序 16socket编程(十一) 套接字I/O超时设置方法 用select实现超时 read_timeout函数封装 write_timeout函数封装 accept_timeout函数封装 connect_timeout函数封装 17socket编程(十二) select限制 poll 18socket编程(十三) epoll使用 epoll与select、poll区别 epoll LT/ET模式 19socket编程(十四) UDP特点 UDP客户/服务基本模型 UDP回射客户/服务器 UDP注意点 20socket编程(十五) udp聊天室实现 21socket编程(十六) UNIX域协议特点 UNIX域地址结构 UNIX域字节流回射客户/服务 UNIX域套接字编程注意点 22socket编程(十七) socketpair sendmsg/recvmsg UNIX域套接字传递描述符字 Linux网络编程之进程间通信篇 23进程间通信介绍(一) 进程同步与进程互斥 进程间通信目的 进程间通信发展 进程间通信分类 进程间共享信息的三种方式 IPC对象的持续性 24进程间通信介绍(二) 死锁 信号量 PV原语 用PV原语解决司机与售票员问题 用PV原语解决民航售票问题 用PV原语解决汽车租赁问题 25System V消息队列(一) 消息队列 IPC对象数据结构 消息队列结构 消息队列在内核中的表示 消息队列函数 26System V消息队列(二) msgsnd函数 msgrcv函数 27System V消息队列(三) 消息队列实现回射客户/服务器 28共享内存介绍 共享内存 共享内存示意图 管道、消息队列与共享内存传递数据对比 mmap函数 munmap函数 msync函数 29System V共享内存 共享内存数据结构 共享内存函数 共享内存示例 30System V信号量(一) 信号量 信号量
Linux网络编程(总共41集) 讲解Linux网络编程知识,分以下四个篇章。 Linux网络编程之TCP/IP基础篇 Linux网络编程之socket编程篇 Linux网络编程之进程间通信篇 Linux网络编程之线程篇 Linux网络编程之TCP/IP基础篇 01TCPIP基础(一) ISO/OSI参考模型 TCP/IP四层模型 基本概念(对等通信、封装、分用、端口) 02TCPIP基础(二) 最大传输单元(MTU)/路径MTU 以太网帧格式 ICMP ARP RARP 03TCPIP基础(三) IP数据报格式 网际校验和 路由 04TCPIP基础(四) TCP特点 TCP报文格式 连接建立三次握手 连接终止四次握手 TCP如何保证可靠性 05TCPIP基础(五) 滑动窗口协议 UDP特点 UDP报文格式 Linux网络编程之socket编程篇 06socket编程(一) 什么是socket IPv4套接口地址结构 网络字节序 字节序转换函数 地址转换函数 套接字类型 07socket编程(二) TCP客户/服务器模型 回射客户/服务器 socket、bind、listen、accept、connect 08socket编程(三) SO_REUSEADDR 处理多客户连接(process-per-conection) 点对点聊天程序实现 09socket编程(四) 流协议与粘包 粘包产生的原因 粘包处理方案 readn writen 回射客户/服务器 10socket编程(五) read、write与recv、send readline实现 用readline实现回射客户/服务器 getsockname、getpeername gethostname、gethostbyname、gethostbyaddr 11socket编程(六) TCP回射客户/服务器 TCP是个流协议 僵进程与SIGCHLD信号 12socket编程(七) TCP 11种状态 连接建立三次握手、连接终止四次握手 TIME_WAIT与SO_REUSEADDR SIGPIPE 13socket编程(八) 五种I/O模型 select 用select改进回射客户端程序 14socket编程(九) select 读、写、异常事件发生条件 用select改进回射服务器程序。 15socket编程(十) 用select改进第八章点对点聊天程序 16socket编程(十一) 套接字I/O超时设置方法 用select实现超时 read_timeout函数封装 write_timeout函数封装 accept_timeout函数封装 connect_timeout函数封装 17socket编程(十二) select限制 poll 18socket编程(十三) epoll使用 epoll与select、poll区别 epoll LT/ET模式 19socket编程(十四) UDP特点 UDP客户/服务基本模型 UDP回射客户/服务器 UDP注意点 20socket编程(十五) udp聊天室实现 21socket编程(十六) UNIX域协议特点 UNIX域地址结构 UNIX域字节流回射客户/服务 UNIX域套接字编程注意点 22socket编程(十七) socketpair sendmsg/recvmsg UNIX域套接字传递描述符字 Linux网络编程之进程间通信篇 23进程间通信介绍(一) 进程同步与进程互斥 进程间通信目的 进程间通信发展 进程间通信分类 进程间共享信息的三种方式 IPC对象的持续性 24进程间通信介绍(二) 死锁 信号量 PV原语 用PV原语解决司机与售票员问题 用PV原语解决民航售票问题 用PV原语解决汽车租赁问题 25System V消息队列(一) 消息队列 IPC对象数据结构 消息队列结构 消息队列在内核中的表示 消息队列函数 26System V消息队列(二) msgsnd函数 msgrcv函数 27System V消息队列(三) 消息队列实现回射客户/服务器 28共享内存介绍 共享内存 共享内存示意图 管道、消息队列与共享内存传递数据对比 mmap函数 munmap函数 msync函数 29System V共享内存 共享内存数据结构 共享内存函数 共享内存示例 30System V信号量(一) 信号量 信号量集结构 信号量集函数 信号量示例 31System V信号量(二) 用信号量实现进程互斥示例 32System V信号量(三) 用信号集解决哲学家就餐问题 33System V共享内存与信号量综合 用信号量解决生产者消费者问题 实现shmfifo 34POSIX消息队列 POSIX消息队列相关函数 POSIX消息队列示例 35PO
Linux网络编程(总共41集) 讲解Linux网络编程知识,分以下四个篇章。 Linux网络编程之TCP/IP基础篇 Linux网络编程之socket编程篇 Linux网络编程之进程间通信篇 Linux网络编程之线程篇 Linux网络编程之TCP/IP基础篇 01TCPIP基础(一) ISO/OSI参考模型 TCP/IP四层模型 基本概念(对等通信、封装、分用、端口) 02TCPIP基础(二) 最大传输单元(MTU)/路径MTU 以太网帧格式 ICMP ARP RARP 03TCPIP基础(三) IP数据报格式 网际校验和 路由 04TCPIP基础(四) TCP特点 TCP报文格式 连接建立三次握手 连接终止四次握手 TCP如何保证可靠性 05TCPIP基础(五) 滑动窗口协议 UDP特点 UDP报文格式 Linux网络编程之socket编程篇 06socket编程(一) 什么是socket IPv4套接口地址结构 网络字节序 字节序转换函数 地址转换函数 套接字类型 07socket编程(二) TCP客户/服务器模型 回射客户 /服务器 socket、bind、listen、accept、connect 08socket编程(三) SO_REUSEADDR 处理多客户连接(process-per-conection) 点对点聊天程序实现 09socket编程(四) 流协议与粘包 粘包产生的原因 粘包处理方案 readn writen 回射客户/服务器 10socket编程(五) read、write与recv、send readline实现 用readline实现回射客户/服务器 getsockname、getpeername gethostname、gethostbyname、gethostbyaddr 11socket编程(六) TCP回射客户/服务器 TCP是个流协议 僵进程与SIGCHLD信号 12socket编程(七) TCP 11种状态 连接建立三次握手、连接终止四次握手 TIME_WAIT与SO_REUSEADDR SIGPIPE 13socket编程(八) 五种I/O模型 select 用select改进回射客户端程序 14socket编程(九) select 读、写、异常事件发生条件 用select改进回射服务器程序。 15socket编程(十) 用select改进第八章点对点聊天程序 16socket编程(十一) 套接字I/O超时设置方法 用select实现超时 read_timeout函数封装 write_timeout函数封装 accept_timeout函数封装 connect_timeout函数封装 17socket编程(十二) select限制 poll 18socket编程(十三) epoll使用 epoll与select、poll区别 epoll LT/ET模式 19socket编程(十四) UDP特点 UDP客户/服务基本模型 UDP回射客户/服务器 UDP注意点 20socket编程(十五) udp聊天室实现 21socket编程(十六) UNIX域协议特点 UNIX域地址结构 UNIX域字节流回射客户/服务 UNIX域套接字编程注意点 22socket编程(十七) socketpair sendmsg/recvmsg UNIX域套接字传递描述符字 Linux网络编程之进程间通信篇 23进程间通信介绍(一) 进程同步与进程互斥 进程间通信目的 进程间通信发展 进程间通信分类 进程间共享信息的三种方式 IPC对象的持续性 24进程间通信介绍(二) 死锁 信号量 PV原语 用PV原语解决司机与售票员问题 用PV原语解决民航售票问题 用PV原语解决汽车租赁问题 25System V消息队列(一) 消息队列 IPC对象数据结构 消息队列结构 消息队列在内核中的表示 消息队列函数 26System V消息队列(二) msgsnd函数 msgrcv函数 27System V消息队列(三) 消息队列实现回射客户/服务器 28共享内存介绍 共享内存 共享内存示意图 管道、消息队列与共享内存传递数据对比 mmap函数 munmap函数 msync函数 29System V共享内存 共享内存数据结构 共享内存函数 共享内存示例 30System V信号量(一) 信
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值