Linux网络编程

进程间的通信:

同一主机内通信
       传统的进程间通信方式(管道(有名,无名),信号)

       IPC对象(共享内存,消息队列,信号量(灯)集)

不同主机间通信

TCP编程基础知识:

1、网络基础 ===》A B C D E 类

IP地址 == 网络位 + 主机位

IP地址的分类: 点分十进制   ipv4

A类       0.    -127.

B类        128. -191.

C类       192. -223.

网关(局域网 门gate)    主机号全是 0(最后一位是1) 子网掩码(全是 0 网络号)

广播                                   主机号全是 255 会给全部网发送信息

端口号:

       编号---16位的数据

       2个字节

       0~65535//65536个数字

作用:

       用来标识 计算机中 用于通信的 某个进程

       IP+端口号==》网络中通信的进程//地址

       通信 两端

       源IP + 源端口 《==》目标IP + 目标端口

通信的四元组

网络链接:

物理层面:有线—WiFi—宽带(光纤)--

网络编程

       open system interconnect

1、OSI 模型  ===》开放系统互联模型  ==》分为7层:

       理想模型  ==》尚未实现

              tftp

              b  /etc/passwd

              a /etc/123

              应用层 

              表示层  加密解密  gzip

              会话层  网络断开,连接状态,keep-close keep-alive

              传输层tcp  udp  协议  文件    视频,音频  ipx

              网络层ip   NAT

              链路层  交换机  数据的格式化  帧 校验

              物理层         100Mb/8  10Gbits   100MB 同轴电缆

              (物理层              发送的是 比特流)

                                   尾|1010 0100|头   ---帧格式

OSI         七层体系结构

IP---->网卡(mac地址)//ip地址 向 mac 地址转换的功能

RARP      //反向

TCP: Transmission Control Protocol(类似 打电话)

特点:1.面向连接  2.可靠传输 3.字节流

面向连接(就是在进行通信之前,必须建立好一条逻辑上的通路)

提供可靠传输(四个“无”,无丢失、无失序、无时差、无重复)

建立连接:

tcp三次握手 目的:建立连接

client      --------------------------   server

1            -------我要通话---------->  1

2            <------恩,你可以--------    2

3            --------恩,好的-------->    3

UDP:(类似 生活中的广播 直播)

特点:1.无连接    2.不可靠       3.数据报

              不提供可靠传输,在数据发送时,不需要建立连接

应用:

(1)、小数据,但是对速度要求较高(qq、及时文本信息、语音等)

(2)、广播、组播

(3)、无线网的传输

socket

  1. socket 函数接口-系统调用
  2. socket 是一种特殊的文件 专门用来 用于“网络通信”

eg:fifo---用于同一主机内的进程间

        socket 用于不同主机间进程的通信

  1. socket是网络通信中,抽象出来的

客户端:

       socket           //买了一部手机

       bind       //可选    socket 绑定 一个 sim卡

       connect         //拨打电话

       write

       read

       close

服务器端

       socket           //买了一部手机

       bind              //绑定 一个 sim卡

       listen             //待机 – 来电了

       accept           //接听电话

       write

       read

       close

socket

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

功能:创建一个新的套接字,用于网络通信。

参数:   @domain      指定套接字的协议族,常见的协议族有AF_INET(IPv4 地址族)、AF_INET6(IPv6 地址族)、AF_UNIX(UNIX 域套接字)等。

@type           指定套接字的类型,常见的类型有SOCK_STREAM(流套接字,用于 TCP)和 SOCK_DGRAM(数据报套接字,用于 UDP)等。

@protocol     指定使用的协议,通常可以传入‘0’,表示让系统根据‘domain’和‘type’参数选择合适的协议。

返回值:       成功       返回       新创建的套接字的文件描述符(File Descriptor)

                     失败       返回       ‘-1’,并设置全局变量errno表示错误原因

connect

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

功能:          连接到远程套接字。

参数:          @ sockfd:要连接的本地套接字的文件描述符。

                     @ addr:指向远程套接字地址结构的指针,

通常是 struct sockaddr 类型的指针

@ addrlen:远程套接字地址结构的长度。

返回值:       如果连接成功,返回 0;

如果出现错误,返回 -1,并设置全局变量 errno 表示具体的错误原因。

bzero

void bzero(void *s, size_t n);

功能:          将指定的内存区域清零,即将该区域内的每个字节都设置为零  
参数:          @ s:指向要清零的内存区域的指针。

                     @ n:要清零的字节数。

返回值:       bzero 函数没有返回值。

inet_addr

in_addr_t inet_addr(const char *cp);

功能:          用于将点分十进制格式的 IPv4 地址转换为网络字节序的二进制格式。

参数:          @ cp:指向点分十进制格式的 IPv4 地址字符串的指针。

返回值:       如果转换成功,则返回一个 in_addr_t 类型的值,该值是网络字节序表示的 IPv4 地址。

如果转换失败,则返回 INADDR_NONE,它是一个特殊的常量,表示转换失败。

bind

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

功能:          将一个地址绑定到一个套接字。

参数:          @ sockfd:套接字描述符,用于标识要绑定地址的套接字。

                     @ addr:指向 struct sockaddr 结构的指针,包含要绑定到套接字的地址信息。

                     @ addrlen:addr 结构的大小(以字节为单位)。

返回值:       执行成功时返回0,

执行失败时返回-1,并设置全局变量 errno 来指示错误的原因。

listen

int listen(int sockfd, int backlog);

功能:          将套接字标记为被动套接字,用于接受连接请求。

参数:          @ sockfd:套接字描述符,用于标识要监听的套接字。

                     @ backlog:指定待处理连接队列的最大长度。

当已建立连接数达到 backlog 时,新的连接将被拒绝或排队等待处理。

返回值:       执行成功时返回0

                        执行失败时返回-1,并设置全局变量 errno 来指示错误的原因。

accept

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

功能:          接受对于绑定到套接字的连接请求,并创建一个新的套接字用于通信。

参数:          @ sockfd:表示服务器套接字的文件描述符,用于标识要接受连接的套接字。

@ addr:指向结构体 sockaddr 的指针,用于存储连接方的地址信息。如果不需要此信息,可以将其设置为 NULL。

                     @ addrlen:表示 addr 指向的地址结构体的长度。

返回值:       若成功则返回一个非负整数,表示新的套接字的文件描述符;

若失败则返回-1,同时设置全局变量 errno 表示错误原因。

创造一个client端

创造一个serve端

通过网络传输文件

客服端:

       socket

       connect

//step1   先把文件名发过去

       struct msg dt;

       dt.len = -1;

       strcpy(dt.data,argv[3]);

       write(fd,&dt,sizeof(struct msg));

close

服务器:

       socket

       bind

       listen

       accept

//接受文件名

tcp 粘包       问题

  1. 手动加一个    分隔符号

buf[ ] = {“1.txt”@#include<stdio.h>}

  1. 指定每次传输的长度    /每次发固定的长度

buf[ ] = { }//10个字节

  1. 用结构体

struct msg
{

        int len;

        char data[256];

};

struct msg dt;

write(fd,&dt,sizeof(struct msg));

struct msg rdt

       read(fd,&rdt,sizeof(struct msg));

recv

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

功能:          从已连接的套接字接收消息。

参数:          @sockfd:已连接的套接字描述符。

                     @buf:用于存储接收到的数据的缓冲区的指针。

                     @len:缓冲区的大小,即要接收的数据的最大字节数。

                     @flags:接收操作的标志,通常为 0 表示阻塞接收

返回值:       成功       返回       接收到的字节数,

错误       则返回   -1。

send

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

功能:          用于发送数据到已连接的套接字

参数:          @sockfd:套接字描述符,指定要发送数据的套接字。

                     @buf:指向要发送数据的缓冲区的指针。

                     @len:要发送的数据的长度,以字节为单位。

@flags:用于控制发送操作的标志位,具体取值取决于系统和网络协议的实现。通常情况下,可以将其设置为 0,表示不启用任何特殊的选项或标志。

返回值          成功       返回       发送的字节数,

错误       返回       -1。

网络编程之 UDP

  1. 特性: 无链接  2.不可靠  3.大数据  
  2. 框架: C/S模式

 server:socket() ===>bind()===>recvfrom()===>close()

 client:socket() ===>bind()===>sendto() ===>close()

recvfrom

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,

struct sockaddr *src_addr, socklen_t *addrlen);

功能:          用于UDP协议中获取对方发送的数据。

参数:          @sockfd 本地的套接字id

                     @buff   要存储数据的内存区,一般是数组或者动态内存。

                     @len    要获取的数据长度,一般是buff的大小。

                     @flags  获取方式,0 阻塞

                     @src_addr 可选,表示对方的地址信息结构体,

如果为NULL,表示不关心对方地址。

                     @addrlen  对方地址信息结构体大小。

                                 如果对方地址是NULL,则该值也为NULL。

返回值:       成功      接收到的数据长度

                     失败     -1;      

sendto

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,

                const struct sockaddr *dest_addr, socklen_t addrlen);

功能:          用于UDP协议中向对方发送数据。

参数:          @sockfd  本地的套接字id

                     @buff    本地的数据存储,一般是要发送的数据。

@len     要发送的数据长度

@flags   要发送数据方式,0 表示阻塞发送。

                 @dest_addr: 必选,表示要发送到的目标主机信息结构体。

                     @addrlen :目标地址长度。

返回值:       成功     发送的数据长度

                 失败     -1;

代码练习

e1用TCP的方式在client 和 server间进行点对点收发信息

//TCP client 端
#include <stdio.h>    
#include <sys/types.h>	    
#include <sys/socket.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>

int main(int argc, const char *argv[])
{
	int fd = socket(AF_INET,SOCK_STREAM,0);

	if(fd < 0)
	{
		perror("socket fail");
		return -1;
	}

	printf("fd = %d\n",fd);

	struct sockaddr_in seraddr;
	bzero(&seraddr,sizeof(seraddr));
	seraddr.sin_family = AF_INET;
	seraddr.sin_port = htons(50002);
	seraddr.sin_addr.s_addr = inet_addr("192.168.1.3");

	if(connect(fd,(const struct sockaddr*)&seraddr,sizeof(seraddr)) < 0)
	{
		perror("connect fail");
		return -1;
	}
	pid_t pid;
	pid = fork();
	if(pid > 0)
	{
		while(1)
		{
			char buf[1024] = {0};
			scanf("%s",buf);
			write(fd,buf,strlen(buf));
			if(strncmp(buf,"quit",4) == 0)
			{
				return 0;
			}
		}
	}
	if(pid == 0)
	{
		while(1)
		{
			char ch[1024] = {0};
			read(fd,ch,sizeof(ch));
			if(strncmp(ch,"quit",4) == 0)
			{
				return 0;
			}
			char resend[1024] = {0};
			sprintf(resend,"ser: %s\n",ch);
			//write(connfd,resend,sizeof(resend));
			write(1,resend,sizeof(resend));
		}
	}

	return 0;
}


//TCP server端
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>


int main(int argc, const char *argv[])
{
	int fd = socket(AF_INET,SOCK_STREAM,0);
	if(fd < 0)
	{
		perror("socket fail");
		return -1;
	}

	struct sockaddr_in seraddr;
	bzero(&seraddr,sizeof(seraddr));
	seraddr.sin_family = AF_INET;
	seraddr.sin_port = htons(50002);
	seraddr.sin_addr.s_addr = inet_addr("192.168.1.3");

	if(bind(fd,(const struct sockaddr*)&seraddr,sizeof(seraddr)) < 0)
	{
		perror("bind fail");
		return -1;
	}

	if(listen(fd,5) < 0)
	{
		perror("listen fail");
		return -1;
	}

	int connfd = 0;
	struct sockaddr_in cliaddr;
	bzero(&cliaddr,sizeof(cliaddr));
	socklen_t len = sizeof(cliaddr);
	char ch[1024] = {0};
	char sh[1024] = {0};

	if((connfd = accept(fd,(struct sockaddr *)&cliaddr,&len)) < 0)
	{
		perror("accept fail");
		return -1;
	}
	printf("connfd = %d\n",connfd);
	puts("-----------------------");
	printf("ip = %s\n",inet_ntoa(cliaddr.sin_addr));
	printf("port = %d\n",ntohs(cliaddr.sin_port));
	puts("-----------------------");
	pid_t pid = fork();
	if(pid < 0)
	{
		perror("fork error");
		return -1;
	}
	if(pid > 0)
	{
		while(1)
		{
			char ch[1024] = {0};
			read(connfd,ch,sizeof(ch));
			if(strncmp(ch,"quit",4) == 0)
			{
				return 0;
			}
			char resend[1024] = {0};
			sprintf(resend,"cli: %s\n",ch);
			//write(connfd,resend,sizeof(resend));
			write(1,resend,sizeof(resend));
		}
	}
	if(pid == 0)
	{
		while(1)
		{
			char buf[1024] = {0};
			scanf("%s",buf);
			write(connfd,buf,strlen(buf));
			if(strncmp(buf,"quit",4) == 0)
			{
				return 0;
			}
		}
	}

	
	return 0;
}


e2.用udp的方式进行点对点聊天

//udp client端
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/wait.h>
#include <pthread.h>
#include <errno.h>


struct sockaddr_in seraddr;

void *do_recv(void *p)
{
	char buf[1024] = {0};
	int *fd = p;
	while(1)
	{
		recvfrom(*fd,buf,sizeof(buf),0,NULL,NULL);
		printf("ser:%s",buf);
		if(strncmp(buf,"quit",4) == 0)
		{
			exit(0);
		}
	}
}

void *do_send(void *p)
{
	char buf[1024] = {0};
	int *fd = p;
	while(1)
	{
		fgets(buf,sizeof(buf),stdin);
		sendto(*fd,buf,sizeof(buf),0,(const struct sockaddr*)&seraddr,sizeof(seraddr));
		if(strncmp(buf,"quit",4) == 0)
		{
			exit(0);
		}
	}
}

int main(int argc, const char *argv[])
{
	//socket
	int fd = socket(AF_INET,SOCK_DGRAM,0);//创造了一个udp协议的socket
	if(fd < 0)
	{
		perror("socket fail");
		return -1;
	}

//	struct sockaddr_in seraddr;
	bzero(&seraddr,sizeof(seraddr));
	seraddr.sin_family = AF_INET;
	seraddr.sin_port = htons(50002);
	seraddr.sin_addr.s_addr = inet_addr("192.168.1.3");

	pthread_t tid[2];
	void *(do_something)[2] = {do_recv,do_send};
	int i = 0;
	int ret = 0;
	for(i = 0; i < 2; ++i)
	{
		ret = pthread_create(&tid[i],NULL,do_something[i],&fd);
		if(ret != 0 )
		{
			errno = ret;
			perror("pthread_create fail");
			return -1;
		}
	}

	pthread_exit(NULL);

	return 0;
}


//udp server端
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/wait.h>
#include <pthread.h>
#include <errno.h>

struct sockaddr_in cliaddr;
socklen_t len;

void do_recv(void *p)
{
	char buf[1024] = {0};
	int *fd = p;
	while(1)
	{
		recvfrom(*fd,buf,sizeof(buf),0,(struct sockaddr*)&cliaddr,&len);
		printf("cli:%s",buf);
		if(strncmp(buf,"quit",4) == 0)
		{
			exit(0);
		}
	}
}

void do_send(void *p)
{
	char buf[1024] = {0};
	int *fd = p;
	while(1)
	{
		fgets(buf,sizeof(buf),stdin);
		sendto(*fd,buf,strlen(buf) + 1,0,(const struct sockaddr*)&cliaddr,sizeof(cliaddr));
		if(strncmp(buf,"quit",4) == 0)
		{
			exit(0);
		}
	}
}

int main(int argc, const char *argv[])
{
	int fd = socket(AF_INET,SOCK_DGRAM,0);
	if(fd < 0)
	{
		perror("socket fail");
		return -1;
	}

	struct sockaddr_in seraddr;
	bzero(&seraddr,sizeof(seraddr));
	seraddr.sin_family = AF_INET;
	seraddr.sin_port = htons(50002);
	seraddr.sin_addr.s_addr = inet_addr("192.168.1.3");

	if(bind(fd,(const struct sockaddr*)&seraddr,sizeof(seraddr)) < 0)
	{
		perror("bind fail");
		return -1;
	}
	
	char buf[1024] = {0};
	bzero(&cliaddr,sizeof(cliaddr));
	len = sizeof(cliaddr);
	
	recvfrom(fd,buf,sizeof(buf),0,(struct sockaddr*)&cliaddr,&len);
	printf("IP = %s\n",inet_ntoa(cliaddr.sin_addr));
	printf("PORT = %d\n",ntohs(cliaddr.sin_port));
	puts("--------------------------");
	
	void *do_something[2] = {do_recv,do_send};
	int i = 0, ret = 0;
	pthread_t tid[2];
	for(i = 0; i < 2; ++i)
	{
		ret = pthread_create(&tid[i],NULL,do_something[i],&fd);
		if(ret != 0)
		{
			errno = ret;
			perror("pthread_create fail");
			return -1;
		}
	}

	pthread_exit(NULL);
	
	return 0;
}




  • 25
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值