一、基于UDP的网络编程模型 服务器端 1、创建socket. 2、将fd和服务器的ip地址和端口号绑定 3、recvfrom阻塞等待接收客户端数据 4、业务处理 5、响应客户端 客户端: 1、创建socket 2、向服务器发送数据sendto 3、阻塞等待服务器的响应信息 4、处理响应信息 5、断开通讯 #include <sys/types.h> #include <sys/socket.h> ssize_t recvfrom(int sockfd,void *buf,size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen); 功能:从一个socket上接收消息 参数: sockfd:指定socket。socket(2)的返回值 buf:存放消息的缓冲区地址 len:指定buf的最大尺寸 flags:0 src_addr:存放的是对面的地址 addrlen:是一个值-结果参数。src_addr的长度 返回值: 成功 返回接收到的字节数 -1 错误 errno被设置 0 对面down机 #include <sys/types.h> #include <sys/socket.h> ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen); 功能:在socket上发送消息 参数: sockfd:指定socket buf:存放数据的缓冲区首地址 len:buf中有效的字节数 flags:0 dest_addr:目标地址 addrlen:目标地址的长度 返回值: -1 错误 errno被设置 成功 返回发送出去的字节数。 编写代码实现基于udp的网络通讯。 代码参见: userv.c uclie.c 172.30.3.93 网络通讯 二、线程的基础 线程 执行的基本单位,线程共享进程的资源 进程 进程是资源分配的基本单位 每个线程有自己的tid。thread_id 每个线程有自己私有的栈帧。 三、线程的创建 系统提供了函数pthread_create(3)用于创建线程 #include <pthread.h> int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); 功能:创建一个新的线程 参数: thread:存放线程id的缓冲区。 attr:NULL 缺省属性 start_routine:线程的执行函数 arg:start_routine函数的唯一参数。 返回值: 0 成功 错误 错误码 Compile and link with -pthread. void *(*start_routine) (void *) 举例说明 创建新的线程 代码参见 pthread_c.c getpid(2)获取进程的pid。 pthread_self(3)来获取线程自己的tid。 #include <pthread.h> pthread_t pthread_self(void); 功能:获取当前线程的id 参数: void 返回值: 返回线程的id。 四、线程退出、汇合、分离 线程的退出 1、return和exit(3)的区别 return只是函数的返回,在线程处理函数中,只是代表了线程的结束。而exit(3)代表的是进程的结束。进程中的所有线程就终止了。 2、使用函数pthread_exit(3)来终止一个线程 #include <pthread.h> void pthread_exit(void *retval); 功能:终止当前线程 参数: retval:指定传递给另一个线程的值,那个线程调用pthread_join(3)接收这个值。 返回值: 不返回给调用者。 3、pthread_cancel(3) #include <pthread.h> int pthread_cancel(pthread_t thread); 功能:给线程发送取消请求 参数: thread:指定了接收请求的线程id。 返回值: 0 成功 非0 错误码 注意:使用pthread_cancel终止的进程,在使用pthread_join(3)获取线程退出信息的时候,获取到的是PTHREAD_CANCELED。 线程的汇合 pthread_join(3)等待线程的汇合 #include <pthread.h> int pthread_join(pthread_t thread, void **retval); 功能:汇合一个终止的线程 参数: thread:指定了等待汇合的线程的id retval: 返回值: 成功 0 失败 返回错误码 举例说明 线程的退出和汇合 代码参见pthread_e.c 线程的分离 pthread_detach(3) #include <pthread.h> int pthread_detach(pthread_t thread); 功能:分离一个线程 参数: thread:指定要分离的线程 返回值: 0 成功 非0 错误码 举例说明 线程的分离 代码参见 pthread_d.c 新建的线程和进程中已经存在的线程是异步的。 这些线程会对公共资源形成竞争。怎么解决竞争? 1、可重入函数 2、让异步的线程同步的访问共享资源。 五、线程同步 条件变量 mutex锁 信号量 举例说明 多个线程异步访问共享资源(临界资源) 代码参见 count.c 使用mutex锁解决临界资源的问题 什么是mutex锁? pthread_mutex_t 是一个类型 mutex锁类型 mutex所是一个互斥设备。 一个mutex锁类型的变量有两中状态 unlocked:不被任何线程拥有 locked:被一个线程拥有 一个mutex锁从来不能被两个线程同时拥有。 如果一个线程想拥有的mutex锁,被另外的线程占用。那么这个线程挂起执行,直到另外线程放弃才能得到。 对临界资源的访问要遵守三歩: 1、先获取mutex锁 2、访问临界资源 3、释放mutex锁 phtread_mutex_init(3) #include <pthread.h> 静态初始化一个mutex锁 pthread_mutex_t fastmutex=PTHREAD_MUTEX_INITIALIZER; int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr); 功能:初始化一个mutex锁 参数: mutex:指定要初始化的mutex锁 mutexattr:NULL 默认 返回值: 0 int pthread_mutex_lock(pthread_mutex_t *mutex); 功能:获取mutex锁,如果这个锁不被其他线程占有,立即返回,拥有了这把锁。将锁的状态改变为locked。 这把锁被其他线程占有。挂起线程,直到其他线程解锁为止。 参数: mutex:指定了要获取的mutex锁 返回值: 非0 错误 0 成功 int pthread_mutex_trylock(pthread_mutex_t *mutex); 功能:获取mutex锁,在其他线程占有这个mutex锁的时候,非阻塞。立即返回,错误。EBUSY 参数: mutex:指定要获取的mutex锁 返回值: 非0 错误 0 成功 int pthread_mutex_unlock(pthread_mutex_t *mutex); 功能:解锁mutex 参数: mutex:释放mutex锁 返回值: 非0 错误 0 成功 int pthread_mutex_destroy(pthread_mutex_t *mutex); 功能:销毁mutex锁 参数: mutex:指定要销毁的mutex锁 返回值: 非0 错误 0 成功 改进count.c。使用mutex锁让进程同步访问临界资源。 总结: 一、基于UDP的编程模型 二、线程的基础 三、线程的创建 四、线程的退出、汇合、分离 五、线程同步 mutex锁