Linux系统编程:TCP/IP网络编程 从socket到通信全解析

目录

tcp协议的网络编程

socket函数

功能

参数

返回值

connect(连接)

功能

参数

返回值

IPv4的地址结构体

网络字节序(大端模式)

字节序的转换函数

htons(端口号)

功能

参数

返回值

inet_addr(IP地址)

功能

参数

返回值

bind(绑定)

功能

参数

返回值

listen(标记)

功能

参数

返回值

accept

功能

参数

返回值

网络编程中专门的读写函数

recv(read)

send(write)

注意

练习


两台主机的进程通信

如何找到网络中的一台主机?

  • IP地址

如何找到该主机上的一个进程?

  • 端口号

编程的接口?

  • 怎么用到系统的网络功能

tcp协议的网络编程

客户端

  • 主动的一方

服务端

  • 被动的一方

socket函数

#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>

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

功能

  • 创建通信的一端

参数

  • @damain:通信范围,AF_UNIX:本地通信;AF_INET:IPv4;AF_INET6:IPv6
  • @type:socket的类型

sock_stream:流式套接字 sock_dgram:用户数据报

  • protocol:协议,表示前面类型对应的具体协议,填0表示走默认协议

sock_stream:默认走的协议是TCP

sock_dgram:默认走的协议是UDP

返回值

  • 成功返回 socket对应的文件描述符
  • 失败返回 -1而且errno被设置

eg:基于tcp协议的socket

int fd = socket(AF_INET,SOCK_STREAM,0);

connect(连接)

#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>

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

功能

  • 发起连接请求

参数

  • @socket:客户端的socket文件描述符
  • @addr:代表服务器端的地址信息
  • @addrlen:addr对用的地址结构体类型的大小

返回值

  • 成功返回 0
  • 失败返回 -1而且errno被设置

IPv4的地址结构体

网络字节序(大端模式)

字节序:大小端?

  • 只要是发到网络中的数据,统一称为网络字节序(大端模式)
  • 接收方收到后,转换为本机的字节序(主机字节序)

字节序的转换函数

  • htons--------------端口号
  • inet_addr---------IP地址
htons(端口号)

uint16_t htons(uint16_t hostshort);

功能
  • 将hostshort主机字节序数值转换为网络字节序
参数
  • @hostshort:要转换的数值
返回值
  • 成功返回 转换好的网络字节序
  • htons(5000);
inet_addr(IP地址)

in_addr_t inet_addr(const char *cp);

功能
  • 将cp传过来的IPv4格式的地址转换为网络序的数值
参数
  • @cp:需要的是一个点分十进制格式的 ip地址 eg:"192.168.1.122"
返回值
  • 成功返回 转换好的网络字节序数值
  • 失败返回 -1
cpp 复制代码
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <strings.h>

//tcp客户服务端
int main(int argc, const char *argv[])
{
	//1.socket
	int fd = socket(AF_INET,SOCK_STREAM,0);
	if(fd < 0)
	{
		perror("socket fail");
		return -1;
	}
	printf("fd:%d\n",fd);
	//2.bind //可选
	//3.connect
	struct sockaddr_in addr;//结构体
	bzero(&addr,sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = inet_addr("192.168.1.139");
	addr.sin_port = htons(50000);
	if(connect(fd,(const struct sockaddr*)&addr,sizeof(addr)) < 0)
	{
		perror("connect fail");
		return -1;
	}
	printf("connect success \n");
	return 0;
}

服务器和客户端进行交互

cpp 复制代码
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <strings.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
//tcp客户服务端
int main(int argc, const char *argv[])
{
	//1.socket
	int fd = socket(AF_INET,SOCK_STREAM,0);
	if(fd < 0)
	{
		perror("socket fail");
		return -1;
	}
	printf("fd:%d\n",fd);
	//2.bind //可选
	//3.connect
	struct sockaddr_in addr;//结构体
	bzero(&addr,sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = inet_addr("192.168.1.139");
	addr.sin_port = htons(50000);
	if(connect(fd,(const struct sockaddr*)&addr,sizeof(addr)) < 0)
	{
		perror("connect fail");
		return -1;
	}
	printf("connect success \n");
#if 0
	char buf[1024] = "hello";
	write(fd,buf,sizeof(buf)); 
#endif
#if 1
	while(1)
	{
		char buf[1024];
		fgets(buf,sizeof(buf),stdin);
		write(fd,buf,strlen(buf)+1);
		if(strncmp(buf,"quit",4)==0)
		{
			break;
		}
		read(fd,buf,sizeof(buf));
		printf("buf:%s\n",buf);
	}
#endif
	return 0;
}

bind(绑定)

  • 服务器端绑定不能省略

#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>

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

功能

  • 绑定一个地址(ip+port)到一个socket文件描述符上

参数

  • @sockfd:socket函数获得的文件描述符
  • @sockaddr:地址信息结构体
  • @addrlen:表示addr参数对应类型的地址信息结构体的大小

返回值

  • 成功返回 0
  • 失败返回 -1而且errno被设置

listen(标记)

#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>

int listen(int sockfd, int backlog);

功能

  • 将sockfd设置为监听套接字

参数

  • @sockfd:socket创建的fd
  • @backlog:队列的大小,最大128

返回值

  • 成功返回 0
  • 失败返回 -1而且errno被设置

accept

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

功能

  • 获取连接请求,建立连接套接字

参数

  • @socket:监听套接字
  • @addr:用来获取对端的地址信息
  • addrlen:值结果参数(注意:必须自己初始化一个值sizeof(addr))

返回值

  • 成功返回 新连接的套接字文件描述符
  • 失败返回 -1而且errno被设置

accept是一个阻塞操作,如果请求连接队列为空,此时accept会阻塞等待

client.c

cpp 复制代码
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <strings.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
//tcp客户服务端
int main(int argc, const char *argv[])
{
	//1.socket
	int fd = socket(AF_INET,SOCK_STREAM,0);
	if(fd < 0)
	{
		perror("socket fail");
		return -1;
	}
	printf("fd:%d\n",fd);
	//2.bind //可选
	//3.connect
	struct sockaddr_in addr;//结构体
	bzero(&addr,sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = inet_addr("127.0.0.1");
	addr.sin_port = htons(50000);
	if(connect(fd,(const struct sockaddr*)&addr,sizeof(addr)) < 0)
	{
		perror("connect fail");
		return -1;
	}
	printf("connect success \n");
#if 0
	char buf[1024] = "hello";
	write(fd,buf,sizeof(buf)); 
#endif
#if 1
	while(1)
	{
		char buf[1024];
		fgets(buf,sizeof(buf),stdin);
		write(fd,buf,strlen(buf)+1);
		if(strncmp(buf,"quit",4)==0)
		{
			break;
		}
	//	read(fd,buf,sizeof(buf));
	//	printf("buf:%s\n",buf);
	}
#endif
	return 0;
}

server.c

cpp 复制代码
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <strings.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
//tcp客户服务端
int main(int argc, const char *argv[])
{
	//1.socket
	int fd = socket(AF_INET,SOCK_STREAM,0);
	if(fd < 0)
	{
		perror("socket fail");
		return -1;
	}
	printf("fd:%d\n",fd);

	//2.bind(绑定)
	struct sockaddr_in addr;//结构体
	bzero(&addr,sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = inet_addr("127.0.0.1");
	addr.sin_port = htons(50000);
	if(bind(fd,(const struct sockaddr*)&addr,sizeof(addr)) < 0)
	{
		perror("bind fail");
		return -1;
	}
	printf("bind success \n");

	//3,listen
	if(listen(fd,5)<0)
	{
		perror("listen fail");
		return -1;
	}
#if 0
	//4.accpet
	int connfd = accept(fd,NULL,NULL);
	if(connfd < 0)
	{
		perror("accept fail");
		return -1;
	}

#endif

	struct sockaddr_in cliaddr;
	bzero(&cliaddr,sizeof(cliaddr));
	socklen_t len = sizeof(cliaddr);
	int connfd = accept(fd,(struct sockaddr*)&cliaddr,&len);
	if(connfd < 0)
	{
		perror("accept fail");
			return -1;
	}
	printf("connfd:%d\n",connfd);
	printf("-------------------\n");
	printf("client ip:%s\n",inet_ntoa(cliaddr.sin_addr));
	printf("client port:%d\n",ntohs(cliaddr.sin_port));
#if 0
	//connect
	char buf[1024] = "hello";
	write(fd,buf,sizeof(buf)); 
#endif
#if 1
	while(1)
	{
		char buf[1024];
		//fgets(buf,sizeof(buf),stdin);
		//write(fd,buf,strlen(buf)+1);
		//if(strncmp(buf,"quit",4)==0)
		//{
		//	break;
		//}
		read(connfd,buf,sizeof(buf));
		printf("buf:%s\n",buf);
	}
#endif
	return 0;
}

网络编程中专门的读写函数

recv(read)

ssize_t recv(int sockfd, void *buf, size_t len, int flags);

send(write)

ssize_t send(int sockfd, const void *buf, size_t len, int flags);

注意

网络中的收发,在tcp中我们主要用的是recv(读)和send(写)

  • recv中的flags一般写0,表示默认方式(阻塞)
  • send中的flags一般写0,表示默认方式

练习

相关推荐
捧月华如1 天前
Linux 系统性能压测工具全景指南(含工程实战)
linux·运维·服务器
s19134838482d1 天前
vlan实验报告
运维·服务器·网络
微涼5301 天前
【Python】在使用联网工具时需要的问题
服务器·python·php
想唱rap1 天前
线程的同步与互斥
linux·运维·服务器·数据库·mysql
格林威1 天前
SSD 写入速度测试命令(Linux)(基于工业相机高速存储)
linux·运维·开发语言·人工智能·数码相机·计算机视觉·工业相机
勇闯逆流河1 天前
【LInux】linux控制(进程替换,自主shell的实现详解)
linux·运维·服务器
IMPYLH1 天前
Linux 的 ls 命令
linux·运维·服务器·bash
笨笨饿1 天前
33_顺序表(待完善)
linux·服务器·c语言·嵌入式硬件·算法·学习方法
Agent产品评测局1 天前
企业发票管理自动化落地,验真归档全流程实现方法:2026企业级智能体选型与实测指南
运维·网络·人工智能·ai·chatgpt·自动化
wwj888wwj1 天前
Ansible基础(复习1)
linux·运维·ansible