UNIX_C 高级编程七
tcp协议和udp协议的比较
tcp协议 —— 传输控制协议,面向链接的协议,类似打电话
—— 建立链接=> 进行通信 => 断开链接
—— 在通信的整个过程中全程保持连接
—— 保证了数据传递的可靠信和有序性(重点)
—— 提供了流量控制,也就是数据接收方会实时通知数据的发送缓冲区的大小
—— 是一种全双工的字节流通信方式
—— 服务器压力比较大,发送数据的效率比较低
udp协议 —— 用户数据报协议,非面向链接的协议,类似写信
—— 不需要全程保持连接
—— 不保证数据传递的可靠性和有序性
—— 不提供流量控制
—— 是全双工的数据报通信方式
—— 服务器压力比较小,发送数据的效率比较高
基于UDP的协议通信模型
服务器端:
1、创建socket,使用socket函数
2、准备通信地址,使用结构体类型;
3、绑定socket和通信地址,使用bind函数
4、进行通信,使用send/sendto/recv/recvfrom函数
5、关闭socket,使用close函数
客户端:
1、创建socket,使用socket函数
2、准备通信地址,使用服务器地址
3、进行通信,使用send/sendto/recv/recvfrom函数
4、关闭socket,使用close函数
ssize_t sendto(int sockfd, const void *buf,size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);
功能:该函数的功能与send函数类型,只不过是通过后两个参数来指定收件人的信息
ssize_trecvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr*src_addr, socklen_t *addrlen);
功能:该函数的功能与recv函数功能相似,只不过是通过后两个参数可以得到客户端/数据发送方的通信地址,相当于来电显示的效果
1 //使用UDP网络模型实现通信3 #include <stdio.h>4 #include <stdlib.h>5 #include <unistd.h>6 #include <sys/types.h>7 #include <netinet/in.h>8 #include <arpa/inet.h>9 #include <sys/socket.h>10 11 int main(void)12 {13 //1.创建socket,使用socket函数14 int sockfd = socket(AF_INET, SOCK_DGRAM, 0);15 if( -1 == sockfd )16 {17 perror("SOCKET");18 exit(-1);19 }20 21 printf("socket 创建成功!\n");22 23 //2.准备通信地址,使用结构体类型24 25 struct sockaddr_in addr;26 addr.sin_family = AF_INET;27 addr.sin_port = htons(8888);28 addr.sin_addr.s_addr = inet_addr("172.30.4.127");29 30 //3.绑定socket通信地址,使用bind函数31 32 int res = bind(sockfd, (struct sockaddr *)&addr, sizeof(addr));33 if(-1== res)34 {35 perror("bind");36 exit(-1);37 }38 39 printf("绑定成功!\n");40 41 //4.进行通信,recv/recvfrom/send/sendto42 43 struct sockaddr_in recv_addr;44 socklen_t len = sizeof(recv_addr);45 46 char buf[100] ={0};47 res = recvfrom(sockfd, buf, sizeof(buf), 0 , (struct sockaddr*)&recv_add r, &len);48 if(-1 == res)49 {50 perror("recv");51 exit(-1);52 }53 54 char * ip = inet_ntoa(recv_addr.sin_addr);55 56 printf("客户端%s发来的消息是:%s, 消息大小是:%d\n", ip, buf, res);57 58 //向客户端回发消息59 res = sendto(sockfd, "I received!", 12, 0, (struct sockaddr*)&recv_addr, len);60 if(-1 == res )61 {62 perror("sendto");63 exit(-1);64 }65 66 printf("成功发送数据到客户端,发送的数据大小是:%d\n", res);67 68 //5.关闭socket,使用close函数69 70 res = close(sockfd);71 if( -1 == res )72 {73 perror("close");74 exit(-1);75 }76 77 return 0;78 }
线程的基本概念
线程隶属于进程,线程是属于进程内部的程序流,目前主流的操作系统都支持多进程,而每个进程的内部有可以支持多线程
进程是重量级的,每个进程都需要独立的内存空间等,因此新建进程对系统资源的消耗比较大,而线程是轻量级的,新建线程会共享所在进程的内存资源等,因此线程对系统资源的消耗比较小,当然每个线程都拥有一块独立的栈区
线程的基本操作
线程的创建
1、pthread_create函数
#include<pthread.h>
intpthread_create(pthread_t *thread, const pthread_attr_t *attr, void*(*start_routine) (void *), void *arg);
参 1:用于将新线程的编号存放在该参数指向的缓冲区中
pthread_t 类型 => typedef unsigned long int pthread_t;
不同系统中对pthtread_t的实现可能不同
参 2:给NULL表示选择默认属性即可
参 3:函数指针类型,新线程的处理函数,也就是新线程启动之后需要去执行的代码;
参 4:用于作为第三个参数所指向函数的实参
返回:成功返回0,失败返回错误编号
功能:主要用于在当前正在调用的进程中创建一个新进程
30 if( 0 != errno )
31 {
32 printf("pthread_careate:%s\n", strerror(errno));
33 exit(-1);
34 }
编译时需要加上-pthread 链接动态库 ( gcc xxx.c -pthread )
线程之间的关系
执行main函数的线程叫做主线程;
使用pthread_create函数创建出来的线程叫做子线程
主线程和子线程之间相互独立,又相互影响,当主线程结束时,会导致进程结束,而进程结束又会导致进程中的所有线程结束
pthread_t pthread_self(void);
功能:主要用于获取当前正在调用线程的编号并返回,没有出错情况
int pthread_equal(pthread_t t1, pthread_tt2);
功能:主要用于判断参数指定的两个线程编号是否相等,如果相等返回非0,否则返回0,没有出错情况
线程的汇合和分离
intpthread_join(pthread_t thread, void **retval);
参 1:线程的编号
惨 2:二级指针类型的返回值
功能:主要用于汇合一个终止的线程,也就是等待第一个参数thread所指向的线程终止,如果该线
+程已经终止,则pthread_join函数立即返回,当然前提条件是:目标线程是可以等待的
+当第二个参数retval不为空时,则该函数会将所等待的目标线程的退出状态信息拷贝到
+*retval所指向的位置
18 return (void*)∑
32 int * pc = NULL;
33
34 errno = pthread_join(thread, (void **)&pc);
intpthread_detach(pthread_t thread);
功能:主要用于将参数指定的线程设置为分离状态,当一个分离状态的线程终止时,会自动释放资源给系统,不需要其它线程的帮助,其他线程也不能用pthread_join函数等待
线程的终止
void pthread_exit(void *retval);
功能:主要用于终止当前正在调用的线程,通过参数返回当前线程的推出状态信息,在同一个进程中的其他线程可以通过pthread_join函数来获取该退出状态信息
线程的取消
int pthread_cancel(pthread_t thread);
功能:主要用于给参数指定的线程发送取消的请求,对于一个新创建的线程老说,默认是可以取消的
intpthread_setcancelstate(int state, int *oldstate);
参 1:用于设置新的状态
PTHREAD_CANCEL_ENABLE —— 可以被取消
PTHREAD_CANCEL_DISABLE —— 不可以被取消
参 2:用于带出旧的状态,给NULL表示不带出函数功能
功能:主要用于设置当前线程是否允许被取消
线程的同步(重点)
基本概念
当多个线程在同一时刻同时访问同一种共享资源时,可能会造成数据的不一致和混乱等问题,此时
+就需要对多个线程进行协调,而线程之间的协调和通信就叫做线程的同步问题
使用互斥量实现线程的同步
定义互斥量 —— pthread_mutex_t mutex;
初始化互斥量 ——pthread_mutex_init( &mutex, NULL );
使用互斥量行加锁 —— pthread_mutex_lock(&mutex);
访问共享资源
使用互斥量进行解锁 —— pthread_mutex_umlock(&mutex);
如果不再使用,则销毁互斥量 —— pthread_mutex_destroy(&mutex);
使用信号量实现线程的同步
信号量 —— 本质就是一种计数器,用于控制同时访问同一种共享资源的进程/线程个数;
当信号量的初始值为1时,效果等同互斥量
#include <semaphore.h>
定义信号量 —— sem_t sem;
初始化信号量 —— sem_init(&sum, 0, 初始值)
获取信号量,也就是信号量减1 —— sem_wait(&sem);
访问共享资源
释放信号量,也就是信号量加1 —— sem_post(&sem);
如果不再使用,则销毁信号量 —— sem_destroy(&sem)
=====================================================================================
终端规范模式开启于关闭,使得缓冲和编辑失效
#include <termios.h>
#include<unistd.h>
int tcgetattr(int fd, structtermios *termios_p);
参 1:设备终端的文件描述符:0——标准输入,1——标准输出,2——标准错误
参 2:struct termios original_mode{
……
tcflag_t c_lflag; //本地模式标志,控制终端编辑功能
cc_t c_cc[NCCS];
};
c_lflag:ICANON —— 使用标准输入模式
eg:original_mode.c_lflag&= ~ICANON —— 去除标准输入模式
ECHO —— 回显功能
eg:original_mode.c_lflag&= ~ECHO —— 关闭回显功能
c_cc[NCCS]:控制字符,用于保存终端驱动程序中的特殊字符,如输入结束符等
NCCS: VMIN —— 非规范模式读取时的最小字符数
eg:original_mode.c_c[VMIN] =1
功能:用于获取与终端相关的参数,返回的结果保存在termios结构体中
int tcsetattr(int fd, int optional_actions, const struct termios*termios_p);
参 1:fd为打开的终端文件描述符,一般给 0;
参 2:optional_actions用于控制修改起作用的时间
* TCSANOW: 不等数据传输完毕就立即改变属性
参 3:而结构体termios_p中保存了要修改的参数
返回:函数在成功的时候返回0,失败的时候返回-1
功能:用于设置终端参数参数参数
5 int _getchar(char * c_num)6 {7 //设置两个结构体用以存储终端相关信息8 struct termios oldmode;9 struct termios newmode;10 11 //获取与终端相关的参数,将结果返回给结构体12 if ( !0 == tcgetattr(0,&oldmode) )13 {14 perror("TCGETATTR ERROR");15 return -1;16 }17 18 //将原来的参数copy给新的结构体用以修改不影响原系统设置 19 newmode = oldmode;20 21 //ICANON摆在哦混输入模式,~ICANON去除该模式22 newmode.c_lflag &= ~ICANON;23 //当输入错误时不希望错误选项回显则23 newmode.c_lflag &= ~ECHO;2324 //AMIN非规范模式设置1,告诉驱动程序一次只读一个字符25 newmode.c_cc[VMIN] = 1;26 27 //在获取输入字符时,使终端模式处于非规模模式下,关闭缓冲与编辑28 if( -1 == tcsetattr(0, TCSANOW, &newmode) )29 { 30 perror("TCSETATTR ERROR");31 return -1;32 }33 34 *c_num = getchar();35 36 //获取成功后还原终端规范模式下37 if ( -1 == tcsetattr(0, TCSANOW, &oldmode) )38 {39 perror("TCGETATTR ERROR");40 return -1;41 }42 43 return 0;44 }45
UNIX_C 高级编程七相关推荐
- ASP 3.0高级编程(七)
来 源: 互联网 作 者: 不祥 发表日期: 2005-12-17 16:35:42 阅读次数: 106 文章标题:ASP → ASP 3.0高级编程(七) 查看权限: 普通文 ...
- 解读经典《C#高级编程》第七版 Page79-93.对象和类型.Chapter3
前言 本篇我们继续讲解本章其余的部分:构造函数.只读字段.匿名类型.结构详解.部分类.静态类.Object类.扩展方法,等. 01 类 构造函数 构造函数是一种特殊的方法: 与类同名 没有返回值,甚至 ...
- 解读经典《C#高级编程》第七版 Page32-38.核心C#.Chapter2
前言 接下来讲讲预定义数据类型.关于数据类型,其实是非常值得透彻研究的. 01 预定义数据类型 值类型和引用类型 C#将把数据类型分为两种,值类型和引用类型,值类型存储在堆栈上,引用类型存储在托管堆上 ...
- 不为人知的网络编程(七):如何让不可靠的UDP变的可靠?
为什么80%的码农都做不了架构师?>>> 本文内容来自学霸君资深架构师袁荣喜的技术分享. 1.前言 最近和很多实时音视频领域的朋友交流中都有谈论到 RUDP(Reliable ...
- (三) 一起学 Unix 环境高级编程 (APUE) 之 文件和目录
. . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...
- c++面向对象高级编程 总目录
本文是对学习侯捷视频 c++面向对象高级编程系列博客的目录总索引. c++面向对象高级编程 学习一 不带指针的类: 访问私有成员变量的方式,内联inline,常量成员函数,构造函数,值传递,引用传递, ...
- 《Unix环境高级编程》学习笔记:从点到面
以前在课堂上学习过<Unix初级教程(第四版)>,对于Unix有了一点了解.由于以后使用的需要,要对它进行比较深入的学习,为此需要阅读不少的书籍,这本<Unix环境高级编程>便 ...
- Unix环境高级编程 笔记
Unix环境高级编程(第二版)学习笔记 这是一次较长时间的整理,然而跳跃了一些章节和很多知识点,仍然是很不完善很不全面的. 前言 操作系统某些问题 严格意义上,可将操作系统定义为一种软件,它控制计算机 ...
- hypermill五轴再加工_【秒杀】hyperMILL2018三四五轴基础到高级编程视频教程,带你快速熟悉五轴编程...
特别申明 本套视频教程为收费教程 特价一天98元 需要本套教程请加微信:16395136 01.hyperMILL 2018 基 础建模视频教程 Hypercad-s教程 第01章:自定义软件 [开] ...
最新文章
- MindInsight计算图可视设计
- python【力扣LeetCode算法题库】面试题59 - II- 队列的最大值
- 微软发布 Windows 10 预览版 Build 21343:此电脑和回收站等启用全新图标
- python在线作业_南开大学20春学期《Python编程基础》在线作业参考答案
- [转载] Java获取一个类继承的父类或者实现的接口的泛型参数
- 【Linux/Ubuntu】查询文件和文件夹大小
- python网络编程-socketserver模块
- 500能不能配个玩英雄联盟的电脑?
- [转]nodejs Error: request entity too large解决方案
- 将时间戳转为中国标准时间
- Android关于Activity屏蔽/拦截Home键
- The Preliminary Contest for ICPC Asia Shanghai 2019 B. Light bulbs(卡了线段树空间的思维题)
- 在Illustrator和手绘文章中创建矢量图形
- 5、流程变量Variables
- Windows系统配置
- 0002数学建模的重要意义
- 校园安防之高清IP摄像头全终端无插件直播视频流媒体服务EasyNVR校园监控系统方案
- vue实例和组件的区别
- 怎么把柱形图和折线图放在一起_EXCEL中统计图表怎么合并在一起?(如柱形图和折线图)...
- 洛谷P1606 Lilypad Pond G