进程间的通信:
同一主机内通信
传统的进程间通信方式(管道(有名,无名),信号)
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
- socket 函数接口-系统调用
- socket 是一种特殊的文件 专门用来 用于“网络通信”
eg:fifo---用于同一主机内的进程间
socket 用于不同主机间进程的通信
- 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 粘包 问题
- 手动加一个 分隔符号
buf[ ] = {“1.txt”@#include<stdio.h>}
- 指定每次传输的长度 /每次发固定的长度
buf[ ] = { }//10个字节
- 用结构体
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
- 特性: 无链接 2.不可靠 3.大数据
- 框架: 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;
}