Linux——TCP编程通信及编程模型
来源:互联网 发布:php输出乱码问题 编辑:程序博客网 时间:2024/06/06 08:31
一.TCP的编程模型
回顾:
TCP的服务器(在案例中使用浏览器作为客户程序)
socket建立服务器的文件描述符号缓冲
bind把IP地址与端口设置到文件描述符号中
listen负责根据客户连接的不同IP与端口,负责生成对应的文件描述符号及其信息
二.TCP通信特点(相对于UDP)
案例3:
有连接:只要连接后,发送数据不用指定IP与端口
数据无边界:TCP数据流,非数据报文.
描述符号双工:
案例4:
使用TCP发送数据注意:
不要以为固定长的数据,一定接收正确,要求使用MSG_WAITALL来保证
案例5:
TCP数据发送的分析:
基本数据int short long float double
结构体数据struct
建议使用MSG_WAITALL
字符串数据以及文件数据等不固定长度的数据怎么发送?
制定数据包:
头:大小固定(数据大小)
体:大小变化(数据)
案例6:
使用TCP传送文件
定义文件数据包.
int 数据大小;
char[]数据
传递文件名
传递数据(循环)
demo1Server.c//接收端
三.TCP服务器编程模式
TCP的服务器端维护多个客户的网络文件描述符号.
对服务器多个客户描述符号同时做读操作,是不可能.需要多任务模型完成.
多任务模型?
1.多进程
2.IO的异步模式(select模式/poll模式)
3.多线程模式
4.多进程池
5.线程池
四.综合应用--多进程应用
1.怎样使用多进程
2.1.建立socket
2.2.连接服务器
2.3.创建CURSES界面
2.4.创建子进程
2.5.在父进程中,输入,发送聊天信息
chatClient.c
总结:
1.TCP的四大特点
2.TCP的数据接收:固定长与变长数据的接收
3.TCP的服务器多进程处理
问题:多进程由于进程资源结构独立.
新进程的文件描述符号的上下文环境在老进程无法访问
回顾:
UDP模型的UML图(一对多)
TCP模型的UML图(一对一)
TCP的服务器(在案例中使用浏览器作为客户程序)
socket建立服务器的文件描述符号缓冲
bind把IP地址与端口设置到文件描述符号中
listen负责根据客户连接的不同IP与端口,负责生成对应的文件描述符号及其信息
accept一旦listen有新的描述符号产生就返回,否则阻塞。
tcp_service.c
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>main(){int serverfd;//总的(服务器)fdint cfd;//客户fdint a;struct sockaddr_in sadr;//服务器地址struct sockaddr_in cadr;//每一个连接者的地址socklen_t len;int r;char buf[1024];//1.socketserverfd=socket(AF_INET,SOCK_STREAM,0);if(serverfd==-1) printf("1:%m\n"),exit(-1);printf("建立服务器socket成功!\n");//2.bindsadr.sin_family=AF_INET;sadr.sin_port=htons(9999);inet_aton("192.168.1.116",&sadr.sin_addr);r=bind(serverfd,(struct sockaddr*)&sadr,sizeof(sadr));if(r==-1) printf("2:%m\n"),exit(-1);printf("服务器地址绑定成功!\n");//3.listen只要有一个新的客户连上来或发送数据 listen就为该客户分配一个内存节点r=listen(serverfd,10);if(r==-1) printf("3:%m\n"),exit(-1); printf("监听服务器成功!\n");//4.accept把listen分配内存的描述符取出来 可以用循环接收多个节点 //这里只接收一个节点(代理客户描述符号)用于测试 len=sizeof(cadr); cfd=accept(serverfd, (struct sockaddr*)&cadr,&len); printf("有人连接:%d,IP:%s:%u\n", cfd,inet_ntoa(cadr.sin_addr), ntohs(cadr.sin_port));//5.处理代理客户描述符号的数据 while(1){ r=recv(cfd,&a,4,MSG_WAITALL);//4字节缓冲填满之后才返回 if(r>0) { //buf[r]=0; printf("::%d\n",a); } if(r==0){ printf("连接断开!\n"); break;}if(r==-1){ printf("网络故障!\n"); break;} }close(cfd);close(serverfd);}
二.TCP通信特点(相对于UDP)
案例3:
有连接:只要连接后,发送数据不用指定IP与端口
数据无边界:TCP数据流,非数据报文.
描述符号双工:
数据准确:TCP协议保证数据完全正确
tcp_client.c
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>main(){int fd;struct sockaddr_in addr;int r;int i=0;//1.socketfd=socket(AF_INET,SOCK_STREAM,0);if(fd==-1) printf("1:%m\n"),exit(-1);printf("建立socket成功!\n");//2.connectaddr.sin_family=AF_INET;addr.sin_port=htons(9999);inet_aton("192.168.1.116",&addr.sin_addr);r=connect(fd,(struct sockaddr*)&addr,sizeof(addr));if(r==-1) printf("2:%m\n"),exit(-1);printf("连接服务器成功!\n");for(i=0;i<20;i++){send(fd,"hello",5,0);//数据没有边界的话 一个数据(结构体)可能分多次接收 //不一定接收20次 如果用UDP就是接收20次}}
案例4:
使用TCP发送数据注意:
不要以为固定长的数据,一定接收正确,要求使用MSG_WAITALL来保证
案例5:
TCP数据发送的分析:
基本数据int short long float double
结构体数据struct
建议使用MSG_WAITALL
字符串数据以及文件数据等不固定长度的数据怎么发送?
制定数据包:
头:大小固定(数据大小)
体:大小变化(数据)
案例6:
使用TCP传送文件
定义文件数据包.
int 数据大小;
char[]数据
传递文件名
传递数据(循环)
传递0长度的数据表示文件结束
domo1Client.c//发送端
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <fcntl.h>main(){int sfd;int ffd;int size;int r;int len;char buf[128];struct sockaddr_in dr;char filename[]="udp_a.c"; //1.建立socketsfd=socket(AF_INET,SOCK_STREAM,0);if(sfd==-1) printf("1:%m\n"),exit(-1);printf("socket成功!\n");//2.连接到服务器dr.sin_family=AF_INET;dr.sin_port=htons(9988);inet_aton("192.168.1.116",&dr.sin_addr);r=connect(sfd,(struct sockaddr*)&dr,sizeof(dr));if(r==-1) printf("2:%m\n"),close(sfd),exit(-1);printf("connect成功!\n");//3.打开文件ffd=open(filename,O_RDONLY);if(ffd==-1) printf("3:%m\n"),close(sfd),exit(-1);printf("open文件成功!\n");//4.发送文件名len=strlen(filename);r=send(sfd,&len,sizeof(len),0);//发送文件名长度r=send(sfd,filename,len,0);//发送文件名 if(r==-1)printf("4:%m\n"),close(ffd),close(sfd),exit(-1);printf("发送文件名成功!\n");//5.循环发送数据while(1){size=read(ffd,buf,128);if(size==-1) break;if(size==0) break;if(size>0){//发送数据长度r=send(sfd,&size,sizeof(size),0);if(r==-1) break;//发送数据r=send(sfd,buf,size,0);if(r==-1) break;}}//6.读取到文件尾,发送0数据包size=0;r=send(sfd,&size,sizeof(size),0);close(ffd);close(sfd);printf("OK!\n");}
demo1Server.c//接收端
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <fcntl.h>main(){int sfd,cfd,ffd;int r;int len;char buf[128];char filename[100];struct sockaddr_in dr;//1.建立服务器socketsfd=socket(AF_INET,SOCK_STREAM,0);if(sfd==-1) printf("1:%m\n"),exit(-1);printf("建立服务器成功!\n");//2.绑定IP地址与端口dr.sin_family=AF_INET;dr.sin_port=htons(9988);dr.sin_addr.s_addr=inet_addr("192.168.180.92");r=bind(sfd,(struct sockaddr*)&dr,sizeof(dr));if(r==-1) printf("2:%m\n"),close(sfd),exit(-1);printf("绑定地址成功!\n");//3.监听r=listen(sfd,10);if(r==-1) printf("3:%m\n"),close(sfd),exit(-1);printf("监听成功!\n");//4.接收连接cfd=accept(sfd,0,0);if(cfd==-1) printf("4:%m\n"),close(sfd),exit(-1);printf("开始接收文件!\n");//5.接收文件名r=recv(cfd,&len,sizeof(len),MSG_WAITALL);printf("文件名长度:%d\n",len);r=recv(cfd,filename,len,MSG_WAITALL);filename[len]=0;printf("传递的文件名是:%s\n",filename);//6.创建文件ffd=open(filename,O_RDWR|O_CREAT,0666);//7.循环接收文件数据while(1){r=recv(cfd,&len,sizeof(len),MSG_WAITALL);if(len==0) break;r=recv(cfd,buf,len,MSG_WAITALL);write(ffd,buf,len);}close(ffd);close(cfd);close(sfd);printf("接收文件完毕!\n");}
三.TCP服务器编程模式
TCP的服务器端维护多个客户的网络文件描述符号.
对服务器多个客户描述符号同时做读操作,是不可能.需要多任务模型完成.
多任务模型?
1.多进程
2.IO的异步模式(select模式/poll模式)
3.多线程模式
4.多进程池
5.线程池
四.综合应用--多进程应用
1.怎样使用多进程
2.多进程的缺陷,以及怎么解决
建立socket
绑定地址
监听
循环接收客户连接
为客户创建子进程
在子进程接收该客户的数据,并且广播
chatServer.c
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <sys/mman.h>int sfd;int *fds;//存放所有客户代理描述符号int idx=0;//客户在数组中下标struct sockaddr_in dr;int r;main(){//1.建立服务器 socketfds=mmap(0,4*100,PROT_READ|PROT_WRITE,MAP_ANONYMOUS|MAP_SHARED,0,0);bzero(fds,sizeof(fds));sfd=socket(AF_INET,SOCK_STREAM,0);if(sfd==-1) printf("1:%m\n"),exit(-1);printf("socket OK!\n");//2.绑定地址dr.sin_family=AF_INET;dr.sin_port=htons(9989);dr.sin_addr.s_addr=inet_addr("192.168.1.116");r=bind(sfd,(struct sockaddr*)&dr,sizeof(dr));if(r==-1) printf("2:%m\n"),exit(-1);printf("bind ok!\n");//3.监听r=listen(sfd,10);if(r==-1) printf("3:%m\n"),exit(-1);printf("listen ok!\n");//4.循环接收客户连接while(1){fds[idx]=accept(sfd,0,0);if(fds[idx]==-1) break;printf("有客户连接:%d\n",fds[idx]);//5.建立一个子进程if(fork()){idx++;continue;}else{//6.子进程任务:接收客户数据并且广播char buf[256];int i;printf("开始接收客户数据:%d\n",fds[idx]);while(1){//接收客户数据r=recv(fds[idx],buf,255,0);printf("%d\n",r);if(r==0){printf("有客户退出\n");close(fds[idx]);fds[idx]=0;break;}if(r==-1){printf("网络故障\n");close(fds[idx]);fds[idx]=0;break;}buf[r]=0;printf("来自客户的数据:%s\n",buf);//广播for(i=0;i<100;i++){if(fds[i]>0){send(fds[i],buf,r,0);}}}exit(0);}}close(sfd);}客户端
2.1.建立socket
2.2.连接服务器
2.3.创建CURSES界面
2.4.创建子进程
2.5.在父进程中,输入,发送聊天信息
2.6.在子进程中,接收服务器传递其他客户聊天信息
chatClient.c
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.<span style="font-size:18px;">建立socket 绑定地址 监听 循环接收客户连接 为客户创建子进程 在子进程接收该客户的数据,并且广播</span>h>#include <curses.h>#include <signal.h>WINDOW*winfo,*wmsg;int fd;int r;struct sockaddr_in dr;int isover=1;int initSocket();void initUI(); void destroy();void handle(int s){int status;wait(&status);destroy();exit(-1);}main(){//printf("网络初始化成功!\n");initUI();r=initSocket();if(r==-1) exit(-1);signal(SIGCHLD,handle);if(fork()){//输入,发送char buf[256];while(1){mvwgetstr(wmsg,1,1,buf);//buf[r]=0;send(fd,buf,strlen(buf),0);//wclear(wmsg);//box(wmsg,0,0);refresh();wrefresh(wmsg);wrefresh(winfo);}}else{//接收,显示char buf[256];int line=1;while(1){r=recv(fd,buf,255,0);if(r==-1) break;if(r==0) break;buf[r]=0;mvwaddstr(winfo,line,1,buf);line++;if(line>=(LINES-3)){wclear(winfo);line=1;box(winfo,0,0);}wmove(wmsg,1,1);touchwin(wmsg);refresh();wrefresh(winfo);wrefresh(wmsg);}exit(-1);}destroy();}void destroy(){close(fd);endwin();}void initUI(){initscr();winfo=derwin(stdscr,(LINES-3),COLS,0,0);wmsg=derwin(stdscr,3,COLS,LINES-3,0);keypad(stdscr,TRUE);keypad(wmsg,TRUE);keypad(winfo,TRUE);box(winfo,0,0);box(wmsg,0,0);refresh();wrefresh(winfo);wrefresh(wmsg);}int initSocket(){fd=socket(AF_INET,SOCK_STREAM,0);if(fd==-1) return -1;dr.sin_family=AF_INET;dr.sin_port=htons(9989);dr.sin_addr.s_addr=inet_addr("192.168.1.116");r=connect(fd,(struct sockaddr*)&dr,sizeof(dr));if(r==-1){close(fd);return -1;}return 0;}
总结:
1.TCP的四大特点
2.TCP的数据接收:固定长与变长数据的接收
3.TCP的服务器多进程处理
问题:多进程由于进程资源结构独立.
新进程的文件描述符号的上下文环境在老进程无法访问
0 0
- Linux——TCP编程通信及编程模型
- Linux网络编程——TCP通信
- linux-socket tcp客户端服务器编程模型及代码详解
- Linux TCP客户端、服务器编程模型及实例
- 【Linux网络编程】TCP/UDP编程模型
- Linux高级编程复习 第十章 TCP编程模型_TCP通信特点_TCP多进程服务器
- Linux网络编程之[基于socket通信的tcp协议的编程模型]
- java socket编程——TCP通信
- Linux 系统应用编程——网络编程(利用TCP/IP 模型分析数据传输过程)
- Linux 系统应用编程——网络编程(利用TCP/IP 模型分析数据传输过程)
- 嵌入式 Linux网络编程(二)——TCP编程模型
- TCP/IP——网络编程模型
- Linux 网络编程——TCP编程
- socket编程 -- 基于TCP协议的C/S通信模型及实现
- Linux网络编程之TCP通信
- [Linux C编程]TCP网络通信
- [Linux C编程]TCP网络通信
- Linux编程网络之TCP通信
- HDU_ACM-2025 查找最大元素
- 求两个排序好的数组的重复项
- php判断上传的文件图片是否为空
- 数组的指针特性
- Android开发之Fragment详解(一)
- Linux——TCP编程通信及编程模型
- Theory:MST -- prim
- Ogre笔记-Ogre基本调用结构
- cocos2d-x 3.0 Win7 + VS2012 下实现贪吃蛇小游戏
- DSP-BIOS使用入门
- ASIHttpRequest——接收的使用方法
- 线性表之顺序表奇偶调整和单链表就地逆置
- mmap实现机制
- 使用Tcl脚本分配FPGA管脚