网络通信总结
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
/*本地通信
#include
#include
#include
server:
1)套接字
int sockfd=socket(AF(PF)_UNIX,SOCK_DGRAM,0);
if(sockfd==-1)perror("创建socket失败:")
2)准备地址
struct sockaddr_un addr;//注意这个结构体
addr.sun_family=AF_LOCAL;//和上面的AF_UNIX前缀要保持一致,可以为AF_UNIX
strcpy(addr.sun_path,"a.sock");//通信介质为a.sock,大小为0和管道原理差不多
/*sun_family和sun_path是这个结构体的两个成员,一个表示协议,另一个为文件路径*/
3)绑定
int res=bind(sockfd,(struct sockaddr*)&addr,sizeof(addr));
4)通信(直接用读写的方式进行通信)
char buf[100]={};
int len=read(sockfd,buf,sizeof(buf));
if(len<=0)perror("读取数据失败\n");
else {printf("读取了%dBytes的数据%s:\n",len,buf);}
5)关闭socket
close(sockfd);
client:
1)套接字
int sockfd=socket(AF(PF)_UNIX,SOCK_DGRAM,0);
if(sockfd==-1)perror("创建socket失败:")
2)准备地址
struct sockaddr_un addr;//注意这个结构体
addr.sun_family=AF_LOCAL;//和上面的AF_UNIX前缀要保持一致,可以为AF_UNIX
strcpy(addr.sun_path,"a.sock");
/*sun_family和sun_path是这个结构体的两个成员,一个表示协议,另一个为文件路径*/
3)连接
int res=connect(sockfd,(struct sockaddr*)&addr,sizeof(addr));
4)通信(直接用读写的方式进行通信)
int len=write(sockfd,"hello",strlen("hello")+1);
if(len<=0)perror("发送失败:");
else printf("成功发送了%dBytes",len);
5)关闭socket
close(sockfd);
UDP:
#include
#include
#include
server:
1)创建socket
int sockfd=socket(AF_INET,SOCK_DGRAM,0);
//注意第一个参数,第二个参数用DGRAM则默认为UDP了
if(sockfd==-1)perror("socket server:"),exit(-1);
2)准备地址
struct sockaddr_in addr;//注意这个结构体后缀
addr.sin_family=AF_INET;
addr.sin_port=htons(10222);
addr.sin_addr.s_addr=INADDR_ANY;
//自己的本机地址可以直接用宏来获取INADDR_ANY
3)绑定
int res=bind(sockfd,(struct sockaddr*)&addr,sizeof(addr));
if(res==-1)perror("绑定失败:"),exit(-1);
else printf("绑定成功\n");
4)通信
char buf[100]={};
struct sockaddr_in fromaddr;
socklen_t len=sizeof(fromaddr);//之所以要这样定义一下再用是为了避免警告
recvfrom(sockfd,buf,sizeof(buf),0,(struct sockaddr*)&fromaddr,&len);
printf("buf=%s\n",buf);
sendto(sockfd,"欢迎你\n",10,0,(struct sockaddr*)&fromaddr,len);
/*5.关闭*/
close(sockfd);
client:
1)创建socket
int sockfd=socket(AF_INET,SOCK_DGRAM,0);
if(sockfd==-1)perror("socket server:"),exit(-1);
2)准备地址
struct sockaddr_in addr;
addr.sin_family=AF_INET;
addr.sin_port=htons(10222);
addr.sin_addr.s_addr=INADDR_ANY;
//自己
的本机地址可以直接用宏来获取INADDR_ANY
/* 3)连接
int res=connect(sockfd,(struct sockaddr*)&addr,sizeof(addr));
if(res==-1)perror("连接失败:"),exit(-1);
printf("连接成功\n");*/(之所以不用连接是下面可以改用另一个接收或发送的函数如
recvfrom/sendto,这其中其实是隐含了连接这一过程(我自己是的理解))
4)通信
//send(sockfd,"你好服务器\n",15,0);
socklen_t len=sizeof(addr);
sendto(sockfd,"你好服务器\n",15,0,(struct sockaddr*)&addr,len);
char buf[100]={};
/*recv和 read几乎一样
recv(sockfd,buf,sizeof(buf),0);
recv不能获取服务器的相关信息所以要改成recvfrom函数,
这个时候服务器是不能向客户端发送信息的
最后一个参数如果给0则和read完全一样了。控制接收的行为*/
recvfrom(sockfd,buf,sizeof(buf),0,(struct sockaddr*)&addr,&len);
printf("服务器说:%s\n",buf);
//send和write几乎完全一样.如果给0则和write完全一样了。控制接收的行为
5)关闭
close(sockfd);
TCP:
server:
1)创建socket
int sockfd=socket(AF_INET,SOCK_STREAM,0);
//只要是写成AF_INET,SOCK_STREAM就会自动用TCP协议
if(sockfd==-1)perror("socket server:"),exit(-1);
2)准备地址
struct sockaddr_in addr;
addr.sin_family=AF_INET;
addr.sin_port=htons(10222);
addr.sin_addr.s_addr=inet_addr("192.168.1.114");
3)绑定
int res=bind(sockfd,(struct sockaddr*)&addr,sizeof(addr));
if(res==-1)perror("绑定失败:"),exit(-1);
printf("绑定成功\n");
4)监听
int r=listen(sockfd,128);//同时允许一百个客户端在等待.最大好像只能是128个
if(r==-1)perror("服务器监听失败:"),exit(-1);
printf("服务器开始服务\n");
5)等待客户端连接
while(1){
struct sockaddr_in fromaddr;
//一定要写成sockaddr_in 而不能写成sockaddr.
socklen_t len=sizeof(fromaddr);
int fd=accept(sockfd,(struct sockaddr*)&fromaddr,&len);
/*返回的是socket不是0或1
第二个参数是用来保存客户端的地址,这是一个输出地址。等待客户端连接
正是这个返回值socket服务端才能和客户端进行通信.*/
if(fd==-1)perror("客户端连接错误:"),exit(-1);
printf("有客户端连接上来了,它是%s\n",inet_ntoa(fromaddr.sin_addr));
//inet_ntoa把网络地址转换成192.....的类型点分十进制形式
/*6.进行通信*/
char buf[100]={};
read(fd,buf,sizeof(buf));
printf("%s说:%s\n",inet_ntoa(fromaddr.sin_addr),buf);
write(fd,"你好客户端\n",strlen("你好客户端\n")+1);
/*7.关闭socket*/
close(fd);
}
close(sockfd);
TCP通信及线程的应用举例:
//server:
#include
#include
#include
#include
#include
#include
#include
void* time_thread(void*p){//线程要做的事
time_t cur=time(0);
char *cur_str=ctime(&cur);
char* msgs[]={
"程序写的好,要饭要到老",
"不知道自己不知道",
"知道自己不知道",
"知道自己知道",
"不知道自己知道"
};
srand(time(0));
char buf[100]={};
sprintf(buf,"%s:%s\n%s\n","当前时间是:",cur_str,msgs[rand()%5]);
int fd=*(int*)p;
write(fd,buf,strlen(buf)+1);
sleep(3);//服务比较复杂,时间比较久
close(fd);
}
int main()
{
/*1.创建socket*/
int sockfd=socket(AF_INET,SOCK_STREAM,0);
//只要是写成AF_INET,SOCK_STREAM就会自动用TCP协议
if(sockfd==-1)perror("socket server:"),exit(-1);
/*2.准备地址*/
struct sockaddr_in addr;
addr.sin_family=AF_INET;
addr.sin_port=htons(10222);
addr.sin_addr.s_addr=inet_addr("192.168.1.114");
/*3.绑定*/
int res=bind(sockfd,(struct sockaddr*)&addr,sizeof(addr));
if(res==-1)perror("绑定失败:"),exit(-1);
printf("绑定成功\n");
/*4.监听*/
int r=listen(sockfd,100);//同时允许一百个客户端在等待.
if(r==-1)perror("服务器监听失败:"),exit(-1);
printf("服务器开始服务\n");
/*5.等待客户端连接*/
while(1){
struct sockaddr_in fromaddr;//一定要写成sockaddr_in 而不能写成sockaddr。
socklen_t len=sizeof(fromaddr);
int fd=accept(sockfd,(struct sockaddr*)&fromaddr,&len);
/*accept返回的是对方的socket不是0或1
第二个参数是用来保存客户端的地址,这是一个输出地址。等待客户端连接
正是这个返回值socket服务端才能和客户端进行通信.*/
if(fd==-1)perror("客户端连接错误:"),exit(-1);
printf("有客户端连接上来了,它是%s\n",inet_ntoa(fromaddr.sin_addr));
//inet_ntoa把网络地址转换成192.....的类型点分十进制形式
/*6.进行通信*/
pthread_t id;
pthread_create(&id,0,time_thread,&fd);
//注意最后一个参数是把accept的返回值给传给线程,其实就是把socket传过去.
/*7.关闭socket*/
}
close(sockfd);
}
/*client*/
#include
#include
#include
#include
#include
#include
int main()
{
/*1.创建socket*/
int sockfd=socket(AF_INET,SOCK_STREAM,0);
//只要是写成AF_INET,SOCK_STREAM就会自动用TCP协议
if(sockfd==-1)perror("socket server:"),exit(-1);
/*2.准备地址,这里必须为服务器的地址,*/
struct sockaddr_in addr;
addr.sin_family=AF_INET;
addr.sin_port=htons(10222);
addr.sin_addr.s_addr=inet_addr("192.168.1.114");
/*3.连接*/
int res=connect(sockfd,(struct sockaddr*)&addr,sizeof(addr));
if(res==-1)perror("连接失败:"),exit(-1);
printf("连接成功\n");
/*4.通信*/
char buf[100]={};
read(sockfd,buf,sizeof(buf));
printf("服务器说:%s\n",buf);
close(sockfd);
}
/**********************************************************************/
协议:protocol
通信协议
TCP/IP
Application
Transport
Internet
Network Interface
ISO 7层模型 ====> 物理层 数据链路层 网络层 传输层 绘话层 表示层 应用层
Socket:
插座,套接字
socket() creates an endpoint for communication and returns a
descriptor
#include
#include
1.创建socket
int socket(int domain, int type, int protocol);{
int domain;{//域,实际是需要指定通信协议
NAME 目的
(或用AF) 如:AF_UNIX, (本地通信其实就是进程间的通信)
(或用AF)PF_UNIX, PF_LOCAL Local communication (本地通信) unix(7)
(AF)PF_INET IPv4 Internet protocols (网络通信IPV4)ip(7)
(AF)PF_INET6 IPv6 Internet protocols (网络通信IPV6)
(AF)PF_IPX IPX - Novell protocols
PF_NETLINK Kernel user interface device netlink(7)
PF_X25 ITU-T X.25 / ISO-8208 protocol x25(7)
PF_AX25 Amateur radio AX.25 protocol
PF_ATMPVC Access to raw ATM PVCs
PF_APPLETALK Appletalk ddp(7)
PF_PACKET Low level packet interface packet(7)
PF_PACKET(底层系统协议和内核通信使用)
}
int type;{//通信类型
SOCK_STREAM 流的方式进进通信 (数据比较安全)用的是TCP协议
Provides sequenced, reliable, two-way, connection-based byte
streams.
An out-of-band data transmission mechanism may be supported
SOCK_DGRAM (本地通信只能用这个)以数据报的方式进行通信 (不安全)UDP协议
Supports datagrams (connectionless, unreliable messages of a fixed
maxi-mum length)
}
int protocol:{//协议
没用,协议已经由第一个参数和第二个参数决定了一般给个0就行
}
返回值:socket描述符,相当于文件描述符,系统将它看成文件描述符,对文件的任何操作都可以用在
socket上
}
2.准备地址
本地地址
#include
struct sockaddr_un{
sun_family;//协议族
sun_path;//文件名
}
网络地址
/*The sockaddr_in structure is used to store addresses for the Internet
address family
the sockaddr_in structure that includes at least the following members
sa_family_t sin_family AF_INET.
in_port_t sin_port Port number.
struct in_addr sin_addr IP address.
the in_addr structure that includes at least the following member:
in_addr_t s_addr
*/
#include
struct sockaddr_in{
addr.sin_family=AF_INET;
addr.sin_port;//端口号
addr.sin_addr;//IP地址
}
端口号:
在一个系统中唯一标识一个执行网络任务的进程的逻辑上的整数值,是short类型(16bit)
表示范围是0~65535,其中1024以下的端口号已经被系统所使用,所以用户只能使用1024以上的端口号
一对多:客户端/服务器 C/S
TCP
面向连接的,也就是客户端和服务端要建立一个网络连接.可靠的
UDP
无连接的,不可靠的,效率稍高
C/S 可以不用连接
但是用sendto/recvfrom 想知道客户端
是哪个就用recvfrom去获取相关的信息
recv/send <==> read/write
//最后一个参数不一样.要是在send或recv的最后一个参数为0时就和后面这个完全一样了
recvfrom / sendto
*****************************************************************/
/*管道通信*/
/*发送端pipesend.c*/
#include
#include
#include
#include
int main()
{
if(mkfifo("a.pipe",0666)==-1)
perror("创建管道文件失败\n"),exit(-1);
int fd=open("a.pipe",O_WRONLY);
if(fd==-1)perror("打开管道文件失败\n"),exit(-1);
int i=0;
for(i=100;i<200;i++){
printf("%d ",i);
sleep(1);
fflush(stdout);
write(fd,&i,sizeof(i));
}
close(fd);
//unlink("a.pipe");//删除管道文件
}
/*接收端piperec.c*/
#include
#include
#include
#include
int main()
{
int fd=open("a.pipe",O_RDONLY);
if(fd==-1)perror("打开文件失败\n"),exit(-1);
int i=0;
for(i=100;i<200;i++){
int x;
read(fd,&x,sizeof(x));
sleep(1);
printf("%d ",x);
fflush(stdout);
}
close(fd);
unlink("a.pipe");
printf("\n");
}
/***************************************************************/
//无名管道
pipewuming.c
#include
#include
#include
int main()
{int fd[2];
//无名管道适合于父子进程间的通信
pipe(fd);
//管道文件在调用pipe时就创建好了。内核中创建管道,并以两种方式(读写)打开文件符就保存在fd中
pid_t pid=fork();
if(pid==0){//子进程
//关闭写端
close(fd[1]);
int i;
for(i=0;i<100;i++)
{
int x;
read(fd[0],&x,sizeof(x));
printf("%d ",x);
fflush(stdout);
}
close(fd[0]);//fd[0]就是读端
exit(0);
}
//父进程
//关闭读端
close(fd[0]);
int i;int x=0;
for(;x<100;)
{
write(fd[1],&x,sizeof(x));
x++;
//sleep(1);
}
close(fd[1]);//fd[1]就是写端
exit(0);
}
*********************************************************************/