wordpress电视直播代码,电商网站建设关键词优化,动漫网站在线免费观看,微博 分享 wordpress一.linux-tcp通信框架
1.基础框架
1.1 tcp 服务器框架
1.套接字
#include sys/socket.h
int socket(int domain, int type, int protocol);
返回的文件描述符可以指向当前的socket#xff0c;后续通过对文件描述符的访问就可以配置这个socket 成功时返回文件…一.linux-tcp通信框架
1.基础框架
1.1 tcp 服务器框架
1.套接字
#include sys/socket.h
int socket(int domain, int type, int protocol);
返回的文件描述符可以指向当前的socket后续通过对文件描述符的访问就可以配置这个socket 成功时返回文件描述符失败时返回-1。 ●domain 套接字中使用的协议族ProtocolFamily信息。 ●type 套接字数据传输类型信息。SOCK_STREAM---TCPSOCKDGRAM---UDP ●protocol 计算机间通信中使用的协议信息。 2.bind 函数
如果把套接字比喻为电话那么创建套接字只安装了电话机。 接着就要给电话机分配号码的方法即给套接字分配 IP地址和端口号。就是用的bind函数。
#includesys/socket.h
int bind(int sockfd, struct sockaddr *myaddr, socklen_t addrlen); 参数一套接字描述符 sockfd 要分配地址信息IP地址和端口号的套接字文件描述符。 参数二myaddr 存有地址信息的结构体变量地址值 struct sockaddr
{ unsigned short sa_family; //2 char sa_data[14]; //14
}; struct in_addr
{In_addr_t s_addr; //32 位 IPv4 地址
};struct sockaddr_in{sa_family//地址族Address Familysa_family_t sin_family;// //地址族Address Familyuint16_t sin_port; // 16 位 TCP/UDP 端口号struct in_addr sin_addr; //32 位 IP 地址char sin_zero[8]; //不使用
} 这里我们使用scokaddr_in来配置端口和ip参数填写更方便然后转换为socketadrr就行两个结构体可以互相转换的 参数三第二个结构体变量的长度 示例配置如下
struct sockaddr_in addr;
char* serv_ip211.217.168.13;//声明 IP地址字符串
char * serv_port9198; //声明端口号字符串
memset(addr,0,sizeof(addr);//结构体变量 addr 的所有成员初始化为 0//指定地址族
addr.sin_family AF_INET;//基于字符串的IP地址初始化
//inet用于将点分十进制的IP地址字符串转换成网络字节顺序big-endian的整数表示形式。
addr.sin_addr.s_addrinet_addr(serv_ip);//基于字符串的端口号初始化
//atoi字符型转换为整型
addr.sin_porthtons(atoi(serv_port));
3.listen 函数
#include sys/socket.h
int listen(int sock,int backlog); sock 希望进入等待连接请求状态的套接字文件描述符 传递的描述符套接字参数成为服务器端 套接字监听套接字。backlog 连接请求等待队列Queue的长度若为5则队列长度为5表示最多使5个连 接请求进入队列。 4.accept 函数
#includesys/socket.h
int accept(int sock,struct sockaddr * addr, socklen_t*addrlen); 成功时返回创建的套接字文件描述符失败时返回-1。 参数sock:服务器套接字的文件描述符。参数addr:保存发起连接请求的客户端地址信息的变量地址值调用函数后向传递来的地址变量参数填充客户端地址信息。参数addrlen第二个参数结构体的长度但是存有长度的变量地址。函数调用完成后该变量即被填客户端地址长度。 accept 函数受理连接请求等待队列中待处理的客户端连接请求。函数调用成功时accept函数内部将产生用于数据I/O的套接字并返回其文件描述符。套接字是自动创建的并自 动与发起连接请求的客户端建立连接。上图展示了accept函数调用过程。
5. tcp 服务端框架
#include stdio.h
#include stdlib.h
#include string.h
#include unistd.h
#include arpa/inet.h
#include sys/socket.hint main(){int serv_sock socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);struct sockaddr_in serv_addr;memset(serv_addr, 0, sizeof(serv_addr));serv_addr.sin_family AF_INET;
/*
在网络编程中一个服务器可能有多个网络接口即多个IP地址。如果你指定了一个具体的
IP地址来绑socket那么服务器程序只能接受发送到这个特定IP地址的连接请求。相反
使用INADDR_ANY可以让服务接受到达服务器上任何网络接口的连接请求
这样就不需要针对每个可能的IP地址分别设置监听了。
*/serv_addr.sin_addr.s_addr htonl(INADDR_ANY); serv_addr.sin_port htons(9190); bind(serv_sock, (struct sockaddr*)serv_addr, sizeof(serv_addr));listen(serv_sock, 20);
//用于生成客户端套接字中间需要使用一个addr结构体我们创建一个空结构体传入
accept辅助完成socket创建struct sockaddr_in clnt_addr;socklen_t clnt_addr_size sizeof(clnt_addr);
//accept后会创建一个套接字int clnt_sock accept(serv_sock, (struct sockaddr*)clnt_addr, clnt_addr_size);char message[] Hello, World!;write(clnt_sock, message, sizeof(message));close(clnt_sock); close(serv_sock); return 0;
}
1.2 tcp 客户端框架
1.connect
#includesys/socket.h
int connect(int sock,struct sockaddr*servaddr, socklen_t addrlen);
成功时返回0失败时返回-1。 sock 客户端套接字文件描述符。servaddr 保存目标服务器端地址信息的变量地址值。addrlen 以字节为单位传递给第二个结构体参数servaddr的地址变量长度。 2.客户端框架
#include stdio.h
#include stdlib.h
#include string.h
#include unistd.h
#include arpa/inet.h
#include sys/socket.hint main(){int sock socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);struct sockaddr_in serv_addr;memset(serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family AF_INET; serv_addr.sin_addr.s_addr inet_addr(127.0.0.1); serv_addr.sin_port htons(9190);
//connect(sock, (struct sockaddr*)serv_addr, sizeof(serv_addr));char buffer[40];read(sock, buffer, sizeof(buffer)-1);printf(Message from server: %s\n, buffer);close(sock);return 0;
}1.3 线程基础
1.线程创建
#includepthread.h
int pthread_create(pthread_t*restrict thread,const pthread_attr_t * restrict attr,void *(* start_routine)(void *),void*restrict arg
); 成功时返回 0失败时返回其他值。 ●thread保存新创建线程ID的变量地址值。线程与进程相同也需要用于区分不同线程的ID。 ●attr用于传递线程属性的参数传递NULL时创建默认属性的线程。 ●start_routine相当于线程main函数的、在单独执行流中执行的函数地址值函数指针。 ●arg通过第三个参数传递调用函数时包含传递参数信息的变量地址值。 #includepthread.h
int pthread_join(pthread_t thread, void ** status); 调用pthread_join 函数的进程或线程将进入等待状态直到第一个参数为ID的线程终 止为止。而且可以得到线程的main函数返回值所以该函数比较有用。下面通过示例了解 该函数的功能。
成功时返回e失败时返回其他值。 thread 该参数值ID的线程终止后才会从该函数返回。status保存线程的main函数返回值的 指针变量地址值。 2.互斥锁
#includepthread.h
int pthread_mutex_init(pthread mutex_t*mutex, const pthread_mutexattr_t* attr);
int pthread_mutex_destroy(pthread_mutex_t * mutex); mutex 创建互斥量时传递保存互斥量的变量地址值销毁时传递需要销毁的互斥量地址值。attr传递即将创建的互斥量属性没有特别需要指定的属性时传递NULL。 #includepthread.h
int pthread_mutex_lock(pthread_mutex_t* mutex);
int pthread_mutex_unlock(pthread mutex_t* mutex); 成功时返回0失败时返回其他值。 使用方法
pthread_mutex_lock(mutex);//临界区的开始
//.....// 临界区的结束
pthreadmutex_unlock(mutex);
线程使用实例
#include stdio.h
#include stdlib.h
#include pthread.h// 全局变量作为共享资源
int shared_resource 0;
// 互斥量对象
pthread_mutex_t mutex;// 线程函数递增共享资源
void* thread_func(void* arg) {for(int i 0; i 10000; i) {// 锁定互斥量pthread_mutex_lock(mutex);// 访问并修改共享资源shared_resource;// 解锁互斥量pthread_mutex_unlock(mutex);}return NULL;
}int main() {pthread_t thread1, thread2;// 初始化互斥量pthread_mutex_init(mutex, NULL);// 创建两个线程pthread_create(thread1, NULL, thread_func, NULL);pthread_create(thread2, NULL, thread_func, NULL);// 等待线程结束pthread_join(thread1, NULL);pthread_join(thread2, NULL);// 打印共享资源的最终值printf(Final value of shared resource: %d\n, shared_resource);// 销毁互斥量pthread_mutex_destroy(mutex);return 0;
}二、并发服务器
2.1 多线程服务器实现
1.服务器端
每次accept都阻塞来一个连接就创建一个线程进行处理多线程互不干扰
#include stdio.h
#include stdlib.h
#include unistd.h
#include string.h
#include arpa/inet.h
#include sys/socket.h
#include netinet/in.h
#include pthread.h
#define BUF_SIZE 100
#define MAX_CLNT 256
void* handle_clnt(void* arg);
void send_msg(char* msg, int len);
void error_handling(char* msg);
int clnt_cnt 0;
int clnt_socks[MAX_CLNT];
pthread_mutex_t mutx;
int main(int argc, char* argv[])
{int serv_sock, clnt_sock;struct sockaddr_in serv_adr, clnt_adr;int clnt_adr_sz;pthread_t t_id;if (argc ! 2) {printf(Usage : %s port\n, argv[0]);exit(1);}pthread_mutex_init(mutx, NULL);serv_sock socket(PF_INET, SOCK_STREAM, 0);memset(serv_adr, 0, sizeof(serv_adr));serv_adr.sin_family AF_INET;serv_adr.sin_addr.s_addr htonl(INADDR_ANY);serv_adr.sin_port htons(atoi(argv[1]));if (bind(serv_sock, (struct sockaddr*)serv_adr, sizeof(serv_adr)) -1)error_handling(bind() error);if (listen(serv_sock, 5) -1)error_handling(listen() error);while (1){clnt_adr_sz sizeof(clnt_adr);clnt_sock accept(serv_sock, (struct sockaddr*)clnt_adr, clnt_adr_sz);pthread_mutex_lock(mutx);clnt_socks[clnt_cnt] clnt_sock;pthread_mutex_unlock(mutx);pthread_create(t_id, NULL, handle_clnt, (void*)clnt_sock);pthread_detach(t_id);printf(Connected client IP: %s \n, inet_ntoa(clnt_adr.sin_addr));}close(serv_sock);return 0;
}
void* handle_clnt(void* arg)
{int clnt_sock *((int*)arg);int str_len 0, i;char msg[BUF_SIZE];while ((str_len read(clnt_sock, msg, sizeof(msg))) ! 0)send_msg(msg, str_len);pthread_mutex_lock(mutx);for (i 0; i clnt_cnt; i)// remove disconnected client{}if (clnt_sock clnt_socks[i]){while (i clnt_cnt - 1)clnt_socks[i] clnt_socks[i 1];break;}clnt_cnt--;pthread_mutex_unlock(mutx);close(clnt_sock);return NULL;
}
void send_msg(char* msg, int len)
{int i;// send to allpthread_mutex_lock(mutx);for (i 0; i clnt_cnt; i)write(clnt_socks[i], msg, len);pthread_mutex_unlock(mutx);
}
void error_handling(char* msg)
{fputs(msg, stderr);fputc(\n, stderr);exit(1);
}
2.客户端
一个主线程即可
#include stdio.h
#include stdlib.h
#include unistd.h
#include string.h
#include arpa/inet.h
#include sys/socket.h
#include pthread.h
#define BUF_SIZE 100
#define NAME_SIZE 20
void* send_msg(void* arg);
void* recv_msg(void* arg);
void error_handling(char* msg);
char name[NAME_SIZE] [DEFAULT];
char msg[BUF_SIZE];
int main(int argc, char* argv[])
{int sock;struct sockaddr_in serv_addr;pthread_t snd_thread, rcv_thread;void* thread_return;if (argc ! 4) {printf(Usage : %s IP port name\n, argv[0]);exit(1);}sprintf(name, [%s], argv[3]);sock socket(PF_INET, SOCK_STREAM, 0);memset(serv_addr, 0, sizeof(serv_addr));serv_addr.sin_family AF_INET;serv_addr.sin_addr.s_addr inet_addr(argv[1]);serv_addr.sin_port htons(atoi(argv[2]));if (connect(sock, (struct sockaddr*)serv_addr, sizeof(serv_addr)) -1)error_handling(connect() error);pthread_create(snd_thread, NULL, send_msg, (void*)sock);pthread_create(rcv_thread, NULL, recv_msg, (void*)sock);pthread_join(snd_thread, thread_return);pthread_join(rcv_thread, thread_return);close(sock);return 0;
}
void* send_msg(void* arg)
{int sock *((int*)arg);// send thread mainchar name_msg[NAME_SIZE BUF_SIZE];while (1){}fgets(msg, BUF_SIZE, stdin);if (!strcmp(msg, q\n) || !strcmp(msg, Q\n)){close(sock);exit(0);}sprintf(name_msg, %s %s, name, msg);write(sock, name_msg, strlen(name_msg));return NULL;
}
void* recv_msg(void* arg)
{int sock *((int*)arg);// read thread mainchar name_msg[NAME_SIZE BUF_SIZE];int str_len;while (1){str_len read(sock, name_msg, NAME_SIZE BUF_SIZE - 1);if (str_len -1)return (void*)-1;name_msg[str_len] 0;fputs(name_msg, stdout);}return NULL;
}
void error_handling(char* msg)
{fputs(msg, stderr);fputc(\n, stderr);exit(1);
}
2.2 select 多路io复用实现
1. 原理及步骤 文件描述符 一开始默认是空的当我们创建socket或者文件时就会从3开始分配文件描述符给相应的socket或者文件
2.select 函数 与fd_set
select
#includesys/select.h#include sys/time.h
int select(int maxfd, fd_set*readset, fd_set* writeset, fd_set*exceptset, const struct
timeval * timeout); 成功时返回大于0的值失败时返回-1。 maxtfd 监视对象文件描述符数量readset用于检查可读性writeset用于检查可写性exceptset用于检查带外数据timeout一个指向timeval 结构的指针用于决定select等待I/O的最长时间。如果为空将 一直等待。 fd_set结构体:
作用用于表示一组文件描述符的集合不要和文件描述符结构混淆 FD_ZEROfdset*fdset∶将 fdset 变量的所有位初始化为0。FD_SETint fdfd set*fdset∶在参数 fdset 指向的变量中注册文件描述符fd的信息。FD_CLRint fdfdset*fdset∶从参数 fdset 指向的变量中清除文件描述符fd的信息。FD_ISSETint fdfd_set*fdset∶若参数 fdset 指向的变量中包含文件描述符fd的信息则 返回真。 3.select实现并发服务器
主要步骤
1.由于serv_sock是最开始创建的那么它一定是最大的文件描述符且只创建了 serv_sock我们将这个文件描述符添加到fd_map中具有能够被select监听的资格但这个监听和listen不是一个东西如果相应文件描述符表示的sock有动作那么select就会结束阻塞开始后面的工作 FD_ZERO(reads);FD_SET(serv_sock, reads);fd_max serv_sock;
2. 进入循环我们将当前的所有得到的文件描述符都放入进行监听
if ((fd_num select(fd_max 1, cpy_reads, 0, 0, timeout)) -1)break;
if (fd_num 0)continue; 3.遍历到最大文件描述符通过FD_SET来判断哪些文件描述符是被激活的导致select不阻塞的同时记得处理时要把这个文件描述符clear掉
for (i 0; i fd_max 1; i){if (FD_ISSET(i, cpy_reads)){if (i serv_sock){// connection request!adr_sz sizeof(clnt_adr);clnt_sock accept(serv_sock, (struct sockaddr*)clnt_adr, adr_sz);FD_SET(clnt_sock, reads);if (fd_max clnt_sock)fd_max clnt_sock;printf(connected client: %d \n, clnt_sock);}else{// read message!str_len read(i, buf, BUF_SIZE);if (str_len 0)// close request!{FD_CLR(i, reads);close(i);printf(closed client: %d \n, i);}else{}}write(i, buf, str_len);}}
完整代码如下
#include stdio.h
#include stdlib.h
#include string.h
#include unistd.h
#include arpa/inet.h
#include sys/socket.h
#include sys/time.h
#include sys/select.h
#define BUF_SIZE 100
void error_handling(char* buf);
int main(int argc, char* argv[])
{int serv_sock, clnt_sock;struct sockaddr_in serv_adr, clnt_adr;struct timeval timeout;fd_set reads, cpy_reads;socklen_t adr_sz;int fd_max, str_len, fd_num, i;char buf[BUF_SIZE];if (argc ! 2) {printf(Usage : %s port\n, argv[0]);exit(1);}serv_sock socket(PF_INET, SOCK_STREAM, 0);memset(serv_adr, 0, sizeof(serv_adr));serv_adr.sin_family AF_INET;serv_adr.sin_addr.s_addr htonl(INADDR_ANY);serv_adr.sin_port htons(atoi(argv[1]));if (bind(serv_sock, (struct sockaddr*)serv_adr, sizeof(serv_adr)) -1)error_handling(bind() error);if (listen(serv_sock, 5) -1)error_handling(listen() error);FD_ZERO(reads);FD_SET(serv_sock, reads);fd_max serv_sock;while (1){cpy_reads reads;timeout.tv_sec 5;timeout.tv_usec 5000;if ((fd_num select(fd_max 1, cpy_reads, 0, 0, timeout)) -1)break;if (fd_num 0)continue;for (i 0; i fd_max 1; i){if (FD_ISSET(i, cpy_reads)){if (i serv_sock){// connection request!adr_sz sizeof(clnt_adr);clnt_sock accept(serv_sock, (struct sockaddr*)clnt_adr, adr_sz);FD_SET(clnt_sock, reads);if (fd_max clnt_sock)fd_max clnt_sock;printf(connected client: %d \n, clnt_sock);}else{// read message!str_len read(i, buf, BUF_SIZE);// close request!if (str_len 0){FD_CLR(i, reads);close(i);printf(closed client: %d \n, i);}else{write(i, buf, str_len);}}}}}close(serv_sock);return 0;
}
void error_handling(char* buf)
{fputs(buf, stderr);fputc(\n, stderr);exit(1);
}
4.客户端
客户端代码和一般客户端无异
#include stdio.h
#include stdlib.h
#include string.h
#include unistd.h
#include arpa/inet.h
#include sys/socket.h
#define BUF_SIZE 1024
void error_handling(char* message);
int main(int argc, char* argv[])
{int sock;char message[BUF_SIZE];int str_len;struct sockaddr_in serv_adr;if (argc ! 3) {printf(Usage : %s IP port\n, argv[0]);exit(1);}sock socket(PF_INET, SOCK_STREAM, 0);if (sock -1)error_handling(socket() error);memset(serv_adr, 0, sizeof(serv_adr));serv_adr.sin_family AF_INET;serv_adr.sin_addr.s_addr inet_addr(argv[1]);serv_adr.sin_port htons(atoi(argv[2]));if (connect(sock, (struct sockaddr*)serv_adr, sizeof(serv_adr)) -1)error_handling(connect() error!);elseputs(Connected...........);while (1){fputs(Input message(Q to quit): , stdout);fgets(message, BUF_SIZE, stdin);if (!strcmp(message, q\n) || !strcmp(message, Q\n))break;write(sock, message, strlen(message));str_len read(sock, message, BUF_SIZE - 1);message[str_len] 0;printf(Message from server: %s, message);}close(sock);return 0;
}
void error_handling(char* message)
{fputs(message, stderr);fputc(\n, stderr);exit(1);
}