2024年最新【Linux】网络篇二--TCP编程_linux之网络编程(tcp)头歌,2024年最新3个月学会Linux运维开发

最全的Linux教程,Linux从入门到精通

======================

  1. linux从入门到精通(第2版)

  2. Linux系统移植

  3. Linux驱动开发入门与实战

  4. LINUX 系统移植 第2版

  5. Linux开源网络全栈详解 从DPDK到OpenFlow

华为18级工程师呕心沥血撰写3000页Linux学习笔记教程

第一份《Linux从入门到精通》466页

====================

内容简介

====

本书是获得了很多读者好评的Linux经典畅销书**《Linux从入门到精通》的第2版**。本书第1版出版后曾经多次印刷,并被51CTO读书频道评为“最受读者喜爱的原创IT技术图书奖”。本书第﹖版以最新的Ubuntu 12.04为版本,循序渐进地向读者介绍了Linux 的基础应用、系统管理、网络应用、娱乐和办公、程序开发、服务器配置、系统安全等。本书附带1张光盘,内容为本书配套多媒体教学视频。另外,本书还为读者提供了大量的Linux学习资料和Ubuntu安装镜像文件,供读者免费下载。

华为18级工程师呕心沥血撰写3000页Linux学习笔记教程

本书适合广大Linux初中级用户、开源软件爱好者和大专院校的学生阅读,同时也非常适合准备从事Linux平台开发的各类人员。

需要《Linux入门到精通》、《linux系统移植》、《Linux驱动开发入门实战》、《Linux开源网络全栈》电子书籍及教程的工程师朋友们劳烦您转发+评论

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以点击这里获取!

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

struct sockaddr
{
u_short sa_family; // 地址族, AF_xxx
char sa_data[14]; // 14字节协议地址
};


我们使用的是:Internet协议地址结构



struct sockaddr_in
{
u_short sin_family; // 地址族, AF_INET,2 bytes
u_short sin_port; // 端口,2 bytes
struct in_addr sin_addr; // IPV4地址,4 bytes
char sin_zero[8]; // 8 bytes unused,作为填充
};
// internet address
struct in_addr
{
in_addr_t s_addr; // u32 network address
};


* `addrLen` : 结构体大小`sizeof (struct sockaddr_in)`


一般用法:



(1)定义一个struct sockaddr_in类型的变量并清空
struct sockaddr_in myaddr;
memset(&myaddr, 0, sizeof(myaddr));
(2)填充地址信息
myaddr.sin_family = PF_INET;
myaddr.sin_port = htons(8888);
myaddr.sin_addr.s_addr = inet_addr(“192.168.1.100”);
(3)将该变量强制转换为struct sockaddr类型在函数中使用
bind(listenfd, (struct sockaddr*)(&myaddr), sizeof(myaddr));




---


#### 4、地址转换函数


(1)主机转网络字序



unsigned long inet_addr(char *address);


`address`是以`’\0’`结尾的`点分IPv4字符串`。该函数返回`32位`的地址数据。  
 如果字符串包含的不是合法的IP地址,则函数返回`-1`。  
 例如:



struct in_addr addr;
addr.s_addr = inet_addr(" 192.168.1.100 ");


(2)网络转主机字序



char* inet_ntoa(struct in_addr address);


`address`是`IPv4地址结构`,函数返回一指向包含点分IP地址的`静态存储区字符指针`。如果`错误`则函数返回`NULL`




---


#### 5、listen函数



int listen (int sockfd, int backlog);


* `sockfd`: 监听连接的套接字
* `backlog`:  
 指定了`正在等待连接`的`最大队列长度`,它的作用在于处理可能同时出现的几个连接请求。



> 
> 返回值: 0 或 -1
> 
> 
> 


完成listen()调用后,socket变成了监听socket(listening socket).




---


#### 6、accept函数



#include <sys/types.h>
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr,
socklen_t *addrlen) ;



> 
> 返回值:已建立好连接的套接字或-1
> 
> 
> 


* `sockfd` : 监听套接字
* `addr` : `对方地址`
* `addrlen`:地址长度




---


#### 7、connect函数



#include <sys/types.h>
#include <sys/socket.h>
int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);



> 
> 返回值:0 或 -1
> 
> 
> 


* `sockfd` : socket返回的文件描述符
* `serv_addr` : `服务器端的地址信息`
* `addrlen` : `serv_addr`的长度


注:  
 `connect()`是客户端使用的系统调用。  
 `listen()`和`accept()`是TCP服务器端使用的函数




---


#### 8、send函数



#include <sys/socket.h>
ssize_t send(int socket, const void *buffer, size_t length, int flags);



> 
> 返回值:`成功`:`实际发送的字节数`,`失败`:`-1`, 并设置`errno`
> 
> 
> 


* `buffer` : 发送缓冲区首地址
* `length` : 发送的字节数
* `flags` : 发送方式(通常为0)  
 一般填写0,此时和write()作用一样  
 特殊的标志:  
 \* `MSG_DONTWAIT`: Enables nonblocking operation; `非阻塞版本`  
 \* `MSG_OOB`:用于发送TCP类型的`带外数据`(out-of-band)




---


#### 9、recv函数



#include <sys/socket.h>
ssize_t recv(int socket, const void *buffer, size_t length, int flags);



> 
> 返回值:`成功`:`实际接收的字节数`,`失败`:`-1`, 并设置`errno`
> 
> 
> 


* `buffer` : 发送缓冲区首地址
* `length` : 发送的字节数
* `flags` : 接收方式(通常为0)
	+ `MSG_DONTWAIT`: Enables nonblocking operation; `非阻塞版本`
	+ `MSG_OOB`:用于发送TCP类型的`带外数据`(out-of-band)
	+ `MSG_PEEK`:  
	 接收消息的开头,但不删除该消息数据。 因此,随后的接收将  
	 返回相同的数据




---


#### 10、read()/write()



ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);


* read()和write()经常会代替recv()和send()
* 通常情况下,看程序员的偏好  
 使用read()/write()和recv()/send()时最好统一




---


#### 11、套接字的关闭



int close(int sockfd); //关闭双向通讯
int shutdown(int sockfd, int howto);


* `TCP连接`是`双向的(是可读写的)`,当我们使用`close`时,会把`读写通道都关闭`,有时侯我们希望`只关闭一个方向`,这个时候我们可以使用`shutdown`。
* 针对不同的howto,系统回采取不同的关闭方式。
	+ `howto = 0`  
	 关闭读通道,但是可以继续往套接字写数据。
	+ `howto = 1`  
	 和上面相反,关闭写通道。只能从套接字读取数据。
	+ `howto = 2`  
	 关闭读写通道,和close()一样




---


### 示例



> 
> `客机向服务器写数据,服务器读数据并打印`
> 
> 
> 


net.h-包含的头文件以及宏定义



/*************************************************************************

File Name: net.h
Author: xiuchengzhen
CSDN: xiuchengzhen.blog.csdn.net
Created Time: Tue 29 Mar 2022 05:45:13 AM PDT
************************************************************************/

#ifndef NET_H
#define NET_H

#include<stdio.h>
#include<stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include<unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include<errno.h>

#define SER_PORT 5001 //端口号
#define SER_ADDR “192.168.125.128” //ip地址
#define BUFSIZE 15 //发送数据的大小(字节)
#define USER_QUIT “quit” (退出命令)

#endif


服务器sever.c:



/*************************************************************************

File Name: sever.c
Author: xiuchengzhen
CSDN: xiuchengzhen.blog.csdn.net
Created Time: Tue 29 Mar 2022 01:41:36 AM PDT
************************************************************************/
#include “net.h”

int main(int argc, const char *argv[])
{
/********socket文件创建***********/
int fd = socket( AF_INET, SOCK_STREAM, 0);
if(fd < 0)
{
perror(“socket”);
exit(-1);
}

/\*\*\*\*\*\*\*bind设置\*\*\*\*\*\*\*/
struct sockaddr\_in sin;
memset(&sin, 0, sizeof(sin));  //清零操作

sin.sin_family = AF_INET; //地址族
sin.sin_port = htons(SER_PORT);

#if 0
sin.sin_addr = inet_addr(SER_ADDR);
#else
if(inet_pton(AF_INET, SER_ADDR, (void *)&sin.sin_addr) == 0)
{
perror(“inet_pton:”);
exit(-1);
}
#endif
if(bind(fd, (struct sockaddr *)&sin,sizeof(sin)) < 0)
{
perror(“bind:”);
exit(-1);
}

/\*\*\*\*\*\*\*\*listen\*\*\*\*\*\*\*\*\*/
if(listen(fd, 5) < 0)
{
	perror("listen:");
	exit(-1);
}

/\*\*\*\*\*\*\*accept阻塞接收\*\*\*\*\*\*\*\*\*/
int newfd;
if((newfd = accept(fd, NULL, NULL)) < 0)
{
	perror("accept:");
	exit(-1);
}

/\*\*\*\*\*\*read\*\*\*\*\*\*\*/
char buf[BUFSIZE];
int ret = -1;
while(1)
{
	bzero((void \*)buf, BUFSIZE);  //清零
	do
	{
		ret = read(newfd, (void \*)buf, BUFSIZE-1);
	}while(ret < 0 && EINTR == errno); //没读到就一直读
	if(ret < 0) //读错误
	{
		perror("read");
		exit(-1);
	}
	if(ret == 0) //连接断开
	{
		printf("client break link!\n");
		break;
	}

	printf("re:%s\n", buf);
	if(strncasecmp(buf, USER_QUIT, strlen(USER_QUIT)) == 0) 
	{
		printf("client choice break link!\n");
		break;
	}
}

/\*\*\*\*\*\*\*\*\*关闭网络\*\*\*\*\*\*\*\*\*\*\*/
close(newfd);
close(fd);

return 0;

}


客机client.c:



/*************************************************************************

File Name: client.c
Author: xiuchengzhen
CSDN: xiuchengzhen.blog.csdn.net
Created Time: Tue 29 Mar 2022 05:43:55 AM PDT
************************************************************************/

#include “net.h”

int main(int argc, const char *argv[])
{
/********socket文件创建***********/
int fd = socket( AF_INET, SOCK_STREAM, 0);
if(fd < 0)
{
perror(“socket”);
exit(-1);
}

/\*\*\*\*\*\*\*connect设置\*\*\*\*\*\*\*/
struct sockaddr\_in sin;
memset(&sin, 0, sizeof(sin));  //清零操作

sin.sin_family = AF_INET;
sin.sin_port = htons(SER_PORT);

#if 0
sin.sin_addr = inet_addr(SER_ADDR);
#else
if(inet_pton(AF_INET, SER_ADDR, (void *)&sin.sin_addr) == 0)
{
perror(“inet_pton:”);
exit(-1);
}
#endif
if(connect(fd, (struct sockaddr *)&sin,sizeof(sin)) < 0)
{
perror(“connect:”);
exit(-1);
}

printf("client connect success!\n");
char buf[BUFSIZE] = {0};
int ret = -1;
while(1)
{
	bzero(buf, 0);
	if(fgets(buf, BUFSIZE-1, stdin) == 0)
	{
		continue;
	}

	do
	{
		ret = write(fd, buf, strlen(buf));
	}while(ret < 0 && EINTR == errno);

	if (!strncasecmp (buf, USER_QUIT, strlen (USER_QUIT))) 
	{
		printf ("Client is exiting!\n");
		break;
	}
}
return 0;

}


运行结果:  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/aa6b293f91e641a6a1c21de5dea426d0.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5L-u5oiQ55yf,size_20,color_FFFFFF,t_70,g_se,x_16)




---


## 二、并发编程


![在这里插入图片描述](https://img-blog.csdnimg.cn/ecff0c398e9b4486ada43a214280c091.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5L-u5oiQ55yf,size_20,color_FFFFFF,t_70,g_se,x_16)



> 
> `主要是应对当多个客机对服务器进行连接的情况`。
> 
> 
> 


* 当一个客机与服务器连接时,服务器创建一个线程或一个子进程为客机单独服务,主函数继续等待新的客机连接




---


### 1、多线程并发


实现过程在上面的例子上稍微改进  
 头文件net.h:



/*************************************************************************

File Name: net.h
Author: xiuchengzhen
CSDN: xiuchengzhen.blog.csdn.net
Created Time: Tue 29 Mar 2022 05:45:13 AM PDT
************************************************************************/

#ifndef NET_H
#define NET_H

#include<stdio.h>
#include<stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include<unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include<errno.h>
#include <netinet/in.h>
#include<pthread.h>

#define SER_PORT 5001
#define SER_ADDR “192.168.125.128”
#define BUFSIZE 15
#define USER_QUIT “quit”
#define BACK_LOG 5

#endif


服务器sever.c:



/*************************************************************************

File Name: sever.c
Author: xiuchengzhen
CSDN: xiuchengzhen.blog.csdn.net
Created Time: Tue 29 Mar 2022 01:41:36 AM PDT
************************************************************************/
#include “net.h”

void *client_hander(void *arg);

int main(int argc, const char *argv[])
{
int i = 0;
/********socket文件创建***********/
int fd = socket( AF_INET, SOCK_STREAM, 0);
if(fd < 0)
{
perror(“socket”);
exit(-1);
}

/\*\*\*\*\*\*\*bind设置\*\*\*\*\*\*\*/
struct sockaddr\_in sin;
memset(&sin, 0, sizeof(sin));  //清零操作

sin.sin_family = AF_INET;
sin.sin_port = htons(SER_PORT);
/\*\*\*\*\*\*\*\*\*\*\*优化1\*\*\*\*\*\*\*\*\*\*/

#if 1
sin.sin_addr.s_addr = htonl(INADDR_ANY); //当系统IP地址发生变化时,这里的地址也会随着变化
#else
if(inet_pton(AF_INET, SER_ADDR, (void *)&sin.sin_addr) == 0)
{
perror(“inet_pton:”);
exit(-1);
}
#endif
if(bind(fd, (struct sockaddr *)&sin,sizeof(sin)) < 0)
{
perror(“bind:”);
exit(-1);
}

/\*\*\*\*\*\*\*\*listen\*\*\*\*\*\*\*\*/
if(listen(fd, BACK_LOG) < 0)  //设置为服务器模式,与最大接收数
{
	perror("listen:");
	exit(-1);
}

/\*\*\*\*\*\*\*\*\*多线程优化\*\*\*\*\*\*\*\*\*/
/\*\*\*\*\*\*\*accept阻塞接收\*\*\*\*\*\*\*\*\*/
while(1)
{

#if 0
int newfd;
if((newfd = accept(fd, NULL, NULL)) < 0)
{
perror(“accept:”);
exit(-1);
}
#else
int newfd[BACK_LOG];
struct sockaddr_in cin;
char client_ip[16] = {0};
socklen_t cin_len = (socklen_t)sizeof(cin);

	memset(&cin, 0, sizeof(cin));

	if((newfd[i] = accept(fd, (struct sockaddr \*)&cin, &cin_len)) < 0)  //阻塞接收
	{
		perror("accept:");
		exit(-1);
	}

	if(inet\_ntop(AF_INET, (void \*)&cin.sin_addr, client_ip, sizeof(cin)) == NULL)
	{
		perror("inet\_ntop:");
		exit(-1);
	}

为了做好运维面试路上的助攻手,特整理了上百道 【运维技术栈面试题集锦】 ,让你面试不慌心不跳,高薪offer怀里抱!

这次整理的面试题,小到shell、MySQL,大到K8s等云原生技术栈,不仅适合运维新人入行面试需要,还适用于想提升进阶跳槽加薪的运维朋友。

本份面试集锦涵盖了

  • 174 道运维工程师面试题
  • 128道k8s面试题
  • 108道shell脚本面试题
  • 200道Linux面试题
  • 51道docker面试题
  • 35道Jenkis面试题
  • 78道MongoDB面试题
  • 17道ansible面试题
  • 60道dubbo面试题
  • 53道kafka面试
  • 18道mysql面试题
  • 40道nginx面试题
  • 77道redis面试题
  • 28道zookeeper

总计 1000+ 道面试题, 内容 又全含金量又高

  • 174道运维工程师面试题

1、什么是运维?

2、在工作中,运维人员经常需要跟运营人员打交道,请问运营人员是做什么工作的?

3、现在给你三百台服务器,你怎么对他们进行管理?

4、简述raid0 raid1raid5二种工作模式的工作原理及特点

5、LVS、Nginx、HAproxy有什么区别?工作中你怎么选择?

6、Squid、Varinsh和Nginx有什么区别,工作中你怎么选择?

7、Tomcat和Resin有什么区别,工作中你怎么选择?

8、什么是中间件?什么是jdk?

9、讲述一下Tomcat8005、8009、8080三个端口的含义?

10、什么叫CDN?

11、什么叫网站灰度发布?

12、简述DNS进行域名解析的过程?

13、RabbitMQ是什么东西?

14、讲一下Keepalived的工作原理?

15、讲述一下LVS三种模式的工作过程?

16、mysql的innodb如何定位锁问题,mysql如何减少主从复制延迟?

17、如何重置mysql root密码?

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以点击这里获取!

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

全含金量又高**

  • 174道运维工程师面试题

1、什么是运维?

2、在工作中,运维人员经常需要跟运营人员打交道,请问运营人员是做什么工作的?

3、现在给你三百台服务器,你怎么对他们进行管理?

4、简述raid0 raid1raid5二种工作模式的工作原理及特点

5、LVS、Nginx、HAproxy有什么区别?工作中你怎么选择?

6、Squid、Varinsh和Nginx有什么区别,工作中你怎么选择?

7、Tomcat和Resin有什么区别,工作中你怎么选择?

8、什么是中间件?什么是jdk?

9、讲述一下Tomcat8005、8009、8080三个端口的含义?

10、什么叫CDN?

11、什么叫网站灰度发布?

12、简述DNS进行域名解析的过程?

13、RabbitMQ是什么东西?

14、讲一下Keepalived的工作原理?

15、讲述一下LVS三种模式的工作过程?

16、mysql的innodb如何定位锁问题,mysql如何减少主从复制延迟?

17、如何重置mysql root密码?

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以点击这里获取!

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 16
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
回答: 在Linux网络编程中,TCP客户端编程的流程类似于打电话的过程。首先需要创建一个用于网络通信的socket套接字,通过调用socket()函数来实现。在创建套接字时,需要指定协议类型为IPv4(AF_INET)和数据流类型为TCP(SOCK_STREAM)。函数的返回值是一个套接字描述符,用于后续的通信操作。\[2\] 接下来,需要连接到服务器端,即拨通对方的号码并确定对方是自己要找的人。通过调用connect()函数来实现。在connect()函数中,需要指定服务器的IP地址和端口号。如果连接成功,就可以开始进行数据的发送和接收。\[2\] 在TCP客户端编程中,还可以使用send()或write()函数来主动发送数据,使用recv()或read()函数来接收对方的回话。发送和接收的具体实现可以根据实际需求进行调整。\[2\] 最后,在通信结束后,需要调用close()函数来关闭套接字,类似于双方说再见挂电话的过程。这样可以释放资源并结束通信。\[2\] 在网络编程中,还需要使用结构体来表示网络地址。在Linux中,常用的网络地址结构体是sockaddr_in。该结构体包含了网络协议类型、端口号、目的地址等信息。\[1\]\[3\] 总结起来,TCP客户端编程的流程包括创建套接字、连接服务器、发送和接收数据以及关闭套接字。在实际编程中,需要使用socket()、connect()、send()、recv()和close()等函数来完成这些操作。同时,还需要使用sockaddr_in结构体来表示网络地址。 #### 引用[.reference_title] - *1* *2* [Linux 网络编程——TCP编程](https://blog.csdn.net/tennysonsky/article/details/45599027)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Linux 网络编程——TCP](https://blog.csdn.net/fansongy/article/details/6778186)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值