C语言实现socket网络编程及多线程编程
文章目录
- 一.概述
- 二.TCP socket网络编程
- 1.server端程序实现(tcp_server.cpp)
- 2.client端程序实现(tcp_client.cpp)
- 3.编译与执行
- 三.UDP socket网络编程
- 1.server端程序实现(udp_server.cpp)
- 2.client端程序实现(udp_client.cpp)
- 3.编译与执行
一.概述
socket网络编程在网络通信中至关重要,因此本文结合socket网络编程和linux多线程编程在linux环境下实现网络通信。实现思路大致如下:server服务端监听某个socket端口等待客户端client连接,在客户端连接成功后创建一个线程(pthread_create)来处理该连接,在主线程中监听客户端的连接,在子线程中处理每个socket连接。
二.TCP socket网络编程
1.server端程序实现(tcp_server.cpp)
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <string.h>
#include <iostream>
#include <pthread.h> //使用多线程头文件
#include <netinet/in.h>using namespace std; //使用标准空间//注意:在socket服务器编程当中有多个文件描述符
//其中socket返回的文件描述符sockfd是用来监听用的,不能读写,而accept返回的文件描述符clifd是用来连接的操作的文件描述符。可以读写操作
/*
//sockaddr_in结构体(用来管理server或者client的socket信息)定义:
struct sockaddr_in{__SOCKADDR_COMMON (sin_); //ipv4 or ipv6in_port_t sin_port; //Port number.struct in_addr sin_addr; //Internet address.// Pad to size of `struct sockaddr'. unsigned char sin_zero[sizeof (struct sockaddr) -__SOCKADDR_COMMON_SIZE -sizeof (in_port_t) -sizeof (struct in_addr)];};
*/
#define SERV_PORT 8010 //服务器端口
#define SERV_ADDR "192.168.1.23" //服务器ip
#define BACKLOG 100 //服务器最多可以监听的客户端数量(最多排队数量)int client_num = 0; //连接的客户端计数//线程1处理函数
void *client_func1(void *clifd_recv)
{int ret = -1;char recv_buf[200]; //定义接收缓存区char send_buf[200]; //定义发送缓存区int clifd = *(int *)clifd_recv; //创建新线程首先获取传入的客户端描述符clifdprintf("有新的客户端 %d 连接成功,子线程1开始工作\r\n",clifd);//5.在连接成功后使用recv函数来接收数据//函数原型:ssize_t recv(int socket, void *buffer, size_t length, int flags);while(1){ret = recv(clifd, recv_buf, sizeof(recv_buf), 0); //接收客户端发送来的数据,注意此处使用的网络描述符是clifdif(ret < 1){cout<<"客户端 "<<clifd<<" 断开了连接"<<endl;cout<<"关闭连接并退出"<<endl;close(clifd); //关闭accept文件描述符clifdclient_num--; //当前服务的客户端数量加一pthread_exit(NULL); //退出当前的线程}cout<<"收到客户端 "<<clifd<<" 发送的数据:len= "<<ret<<" buf= "<<recv_buf<<endl;memset(recv_buf,0,sizeof(recv_buf)); //清空接收缓存区//6.使用send函数发生数据strcpy(send_buf,"hello client1!");ret = send(clifd, send_buf, strlen(send_buf), 0);cout<<"发送了"<<ret<<"个数据"<<endl;memset(send_buf,0,sizeof(send_buf)); //清空接收缓存区}
}//线程2处理函数
void *client_func2(void *clifd_recv)
{int ret = -1;char recv_buf[200]; //定义接收缓存区char send_buf[200]; //定义发送缓存区int clifd = *(int *)clifd_recv; //创建新线程首先获取传入的客户端描述符clifdprintf("有新的客户端 %d 连接成功,子线程2开始工作\r\n",clifd);//5.在连接成功后使用recv函数来接收数据//函数原型:ssize_t recv(int socket, void *buffer, size_t length, int flags);while(1){ ret = recv(clifd, recv_buf, sizeof(recv_buf), 0); //接收客户端发送来的数据,注意此处使用的网络描述符是clifdif(ret < 1){cout<<"客户端 "<<clifd<<" 断开了连接"<<endl;cout<<"关闭连接并退出"<<endl;close(clifd); //关闭accept文件描述符clifdclient_num--; //当前服务的客户端数量加一pthread_exit(NULL); //退出当前的线程}cout<<"收到客户端 "<<clifd<<" 发送的数据:len= "<<ret<<" buf= "<<recv_buf<<endl;memset(recv_buf,0,sizeof(recv_buf)); //清空接收缓存区//6.使用send函数发生数据strcpy(send_buf,"hello client2!!");ret = send(clifd, send_buf, strlen(send_buf), 0);cout<<"发送了"<<ret<<"个数据"<<endl;memset(send_buf,0,sizeof(send_buf)); //清空接收缓存区}
}//线程3处理函数
void *client_func3(void *clifd_recv)
{int ret = -1;char recv_buf[200]; //定义接收缓存区char send_buf[200]; //定义发送缓存区int clifd = *(int *)clifd_recv; //创建新线程首先获取传入的客户端描述符clifdprintf("有新的客户端 %d 连接成功,子线程3开始工作\r\n",clifd);//5.在连接成功后使用recv函数来接收数据//函数原型:ssize_t recv(int socket, void *buffer, size_t length, int flags);while(1){ ret = recv(clifd, recv_buf, sizeof(recv_buf), 0); //接收客户端发送来的数据,注意此处使用的网络描述符是clifdif(ret < 1){cout<<"客户端 "<<clifd<<" 断开了连接"<<endl;cout<<"关闭连接并退出"<<endl;close(clifd); //关闭accept文件描述符clifdclient_num--; //当前服务的客户端数量加一pthread_exit(NULL); //退出当前的线程}cout<<"收到客户端 "<<clifd<<" 发送的数据:len= "<<ret<<" buf= "<<recv_buf<<endl;memset(recv_buf,0,sizeof(recv_buf)); //清空接收缓存区//6.使用send函数发生数据strcpy(send_buf,"hello client3!!!");ret = send(clifd, send_buf, strlen(send_buf), 0);cout<<"发送了"<<ret<<"个数据"<<endl;memset(send_buf,0,sizeof(send_buf)); //清空接收缓存区}
}int main(int argc,char **argv)
{int ret = -1;int sockfd = -1; //定义socket网络文件描述符int clifd = -1; //定义accept网络文件描述符pthread_t th = -1; //定义一个多线程创建句柄struct sockaddr_in servaddr={0}; //服务器sockaddr_in定义成ipv4类型的服务器ip结构体(ipv6是sockaddr_inv6)struct sockaddr_in cliaddr={0}; //客户端sockaddr_insocklen_t address_len = 0; //客户端长度//1.首先使用socket函数创建网络文件描述符(类似于文件IO中的open函数)//函数原型:int socket(int domain, int type, int protocol); sockfd = socket(AF_INET, SOCK_STREAM, 0); //ipv4,TCP,系统自动选择protocolif(sockfd < 0){cout<<"创建socket文件描述符失败"<<endl;_exit(-1);}cout<<"sockfd="<<sockfd<<endl;//注意:由TCP套接字状态TIME_WAIT引起在结束本次会话后close立刻开启下次会话会Bind失败。//该状态在套接字关闭后约保留 2 到 4 分钟。在 TIME_WAIT 状态退出之后,套接字被删除,该地址才能被重新绑定而不出问题。//因此下面两句话的加入可以解决这个问题int on = 1;ret = setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) );//2.使用bind函数绑定socket文件描述符和相关参数//函数原型:int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen); servaddr.sin_family = AF_INET; //定义servaddr的domain地址族为ipv4servaddr.sin_port = htons(SERV_PORT); //定义servaddr的portnum为SERV_PORT(8010),host to net shortservaddr.sin_addr.s_addr = inet_addr(SERV_ADDR); //定义servaddr的address为SERV_ADDR(192.168.1.23) person----->u32//servaddr.sin_addr.s_addr = INADDR_ANY; //监听该电脑的所有IPmemset(servaddr.sin_zero,0,sizeof(servaddr.sin_zero)); //设置servaddr的sin_zero区域为0ret = bind(sockfd, (const struct sockaddr *)&servaddr,sizeof(servaddr)); //使用bind函数绑定socket文件描述符和相关参数if(ret < 0){cout<<"bind函数绑定socket文件描述符失败"<<endl;_exit(-1);}cout<<"bind绑定成功"<<endl;//3.使用listen函数进行接收监听(监听当前设置的ip地址下的端口号port)//函数原型:int listen(int socket, int backlog);ret = listen(sockfd, BACKLOG); //sockfd,等待列表,最多可以排队排BACKLOG(100)个if(ret < 0){cout<<"listen监听失败"<<endl;_exit(-1);}cout<<"listen监听成功,等待客户端连接:"<<endl;while(1){//4.使用accept函数阻塞等待客户端连接,注意:会阻塞!!!//函数原型:int accept(int socket, struct sockaddr *restrict address,socklen_t *restrict address_len);address_len = sizeof(struct sockaddr); //给client_len赋值clifd = accept(sockfd, (struct sockaddr *)&cliaddr,&address_len); //此时会阻塞在这监听客户端连接if(clifd < 0){cout<<"accept连接客户端失败"<<endl;_exit(-1);}cout<<"listen连接客户端成功,clifd ="<<clifd<<endl;cout<<"客户端端口号port= "<<ntohs(cliaddr.sin_port)<<endl;cout<<"客户端ip= "<<inet_ntoa(cliaddr.sin_addr)<<endl;//在收到客户端连接成功后创建一个新的线程,在线程里进行数据收发client_num++; //当前服务的客户端数量加1switch(client_num){case 1:ret = pthread_create(&th, NULL, client_func1, (void *)(&clifd)); //创建一个线程client_func,将客户端描述符clifd作为参数传递给多线程处理函数break;case 2:ret = pthread_create(&th, NULL, client_func2, (void *)(&clifd));break;case 3:ret = pthread_create(&th, NULL, client_func3, (void *)(&clifd));break;default:cout<<"连接的客户端数量超过3台,停止服务"<<endl;break;}if(ret == 0){printf("创建线程 %d 成功,有新的客户端 %d 连接成功,线程创建成功\r\n",(int)th,clifd);pthread_detach(th); //在线程创建成功后使用pthread_detach分离子线程,这样就可以在子线程退出后自动回收子线程资源了}else{printf("线程创建失败\r\n");_exit(-1);}}cout<<"所有线程全部关闭,退出"<<endl;close(sockfd); //关闭socket文件描述符return 0;
}
2.client端程序实现(tcp_client.cpp)
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <string.h>
#include <iostream>using namespace std; //使用标准空间
/*
//sockaddr_in结构体定义:
struct sockaddr_in{__SOCKADDR_COMMON (sin_); //ipv4 or ipv6in_port_t sin_port; //Port number.struct in_addr sin_addr; //Internet address.// Pad to size of `struct sockaddr'. unsigned char sin_zero[sizeof (struct sockaddr) -__SOCKADDR_COMMON_SIZE -sizeof (in_port_t) -sizeof (struct in_addr)];};
*/
#define SERV_PORT 8010 //服务器端口
#define SERV_ADDR "192.168.1.23" //服务器ip
#define CLI_ADDR "192.168.1.50" //服务器开放给我们的ip地址
char recv_buf[1000]; //定义接收缓存区
char send_buf[1000]; //定义发送缓存区
int main(int argc,char **argv)
{int ret = -1;int sockfd = -1; //定义网络文件描述符struct sockaddr_in servaddr={0}; //服务器sockaddr_in定义成ipv4类型的服务器ip结构体(ipv6是sockaddr_inv6)//1.首先使用socket函数创建网络文件描述符(类似于文件IO中的open函数)//函数原型:int socket(int domain, int type, int protocol); sockfd = socket(AF_INET, SOCK_STREAM, 0); //ipv4,TCP,系统自动选择protocolif(sockfd < 0){cout<<"创建socket文件描述符失败"<<endl;_exit(-1);}cout<<"sockfd="<<sockfd<<endl;//2.使用connect函数连接服务器//函数原型:int connect(int socket, const struct sockaddr *address,socklen_t address_len);servaddr.sin_family = AF_INET; //定义servaddr的domain地址族为ipv4servaddr.sin_port = htons(SERV_PORT); //定义servaddr的portnum为SERV_PORT(8010),host to net shortservaddr.sin_addr.s_addr = inet_addr(SERV_ADDR); //定义servaddr的address为SERV_ADDR(192.168.1.23) person----->u32ret = connect(sockfd, (const struct sockaddr *)&servaddr,sizeof(servaddr));if(ret < 0){cout<<"客户端connect服务器失败"<<endl;_exit(-1);}cout<<"客户端connect服务器成功"<<endl;//下面客户端和服务器互相收发while(1){//6.使用send函数发生数据cout<<"请输入要发送给服务器的内容:";cin >> send_buf;if(!strncmp(send_buf,"+++",3))break;ret = send(sockfd, send_buf, strlen(send_buf), 0);cout<<"发送了"<<ret<<"个数据"<<endl;memset(send_buf,0,sizeof(send_buf)); //清空接收缓存区ret = recv(sockfd, recv_buf, sizeof(recv_buf), 0); //接收客户端发送来的数据,注意此处使用的网络描述符是clifdif(ret < 1){cout<<"服务器断开了连接"<<endl;break;}cout<<"收到服务器发送的数据:len= "<<ret<<" buf= "<<recv_buf<<endl;memset(recv_buf,0,sizeof(recv_buf)); //清空接收缓存区}cout<<"关闭连接并退出"<<endl;close(sockfd); //关闭socket文件描述符return 0;
}
3.编译与执行
g++ tcp_server.cpp -o server -pthread
g++ tcp_client.cpp -o client
#arm-linux-gnueabihf-g++ tcp_server.cpp -o server
#arm-linux-gnueabihf-g++ tcp_client.cpp -o client
其中g++编译器编译出的文件在x86架构处理器运行,arm-linux-gnueabihf-g++编译出的文件在ARM架构处理器运行。另注意用到多线程pthread时编译需要链接pthread库。
编译完成后,先后运行服务器程序./server和客户端程序./client程序,进行数据交互。
三.UDP socket网络编程
1.server端程序实现(udp_server.cpp)
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <string.h>
#include <iostream>
#include <netinet/in.h>using namespace std; //使用标准空间
//在使用UDP网络编程的时候,由于UDP非面向连接,因此不需要listen和accept。因此可以简单总结UDP server端的程序编写流程如下:
//1.socket创建fd
//2.bind绑定server端的socket信息
//3.直接调用recvfrom函数接收来自客户端的消息,同时读取客户端的信息并保存在cliaddr结构体中,以便下次发送消息的时候可以准确找到对方
//4.调用sendto函数给客户端返回信息,需要用到刚刚接收的cliaddr信息(因为服务器可能被多个客户端连接,因此不知道发给谁,只能根据cliaddr信息使用sendto发送)#define SERV_PORT 8010 //服务器端口
#define SERV_ADDR "192.168.1.23" //服务器ip
#define BACKLOG 100 //服务器最多可以监听的客户端数量(最多排队数量)int main(int argc,char **argv)
{int ret = -1;int sockfd = -1; //定义socket网络文件描述符int recv_len; //接收数据长度int send_len; //发送数据长度char recv_buf[200]; //定义接收缓存区char send_buf[200]; //定义发送缓存区struct sockaddr_in servaddr={0}; //服务器sockaddr_in定义成ipv4类型的服务器ip结构体(ipv6是sockaddr_inv6)struct sockaddr_in cliaddr={0}; //客户端sockaddr_insocklen_t address_len = 0; //客户端长度//1.首先使用socket函数创建网络文件描述符(类似于文件IO中的open函数)//函数原型:int socket(int domain, int type, int protocol); sockfd = socket(AF_INET, SOCK_DGRAM, 0); //ipv4,UDP,系统自动选择protocolif(sockfd < 0){cout<<"创建socket文件描述符失败"<<endl;_exit(-1);}cout<<"sockfd="<<sockfd<<endl;//注意:由TCP套接字状态TIME_WAIT引起在结束本次会话后close立刻开启下次会话会Bind失败。//该状态在套接字关闭后约保留 2 到 4 分钟。在 TIME_WAIT 状态退出之后,套接字被删除,该地址才能被重新绑定而不出问题。//因此下面两句话的加入可以解决这个问题int on = 1;ret = setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) );//2.使用bind函数绑定socket文件描述符和相关参数//函数原型:int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen); servaddr.sin_family = AF_INET; //定义servaddr的domain地址族为ipv4servaddr.sin_port = htons(SERV_PORT); //定义servaddr的portnum为SERV_PORT(8010),host to net shortservaddr.sin_addr.s_addr = inet_addr(SERV_ADDR); //定义servaddr的address为SERV_ADDR(192.168.1.23) person----->u32//servaddr.sin_addr.s_addr = INADDR_ANY; //监听该电脑的所有IPmemset(servaddr.sin_zero,0,sizeof(servaddr.sin_zero)); //设置servaddr的sin_zero区域为0ret = bind(sockfd, (const struct sockaddr *)&servaddr,sizeof(servaddr)); //使用bind函数绑定socket文件描述符和相关参数if(ret < 0){cout<<"bind函数绑定socket文件描述符失败"<<endl;_exit(-1);}cout<<"bind绑定成功"<<endl;while(1){//3.使用recvfrom函数接收客户端发送的数据,返回接收数据长度//入口参数:fd,reve_buf,recv_len,flag,clinet_addr,clinet_lenaddress_len = sizeof(struct sockaddr);recv_len = recvfrom(sockfd, recv_buf, sizeof(recv_buf),0,(struct sockaddr *)&cliaddr,&address_len);if(recv_len > 0) //判断接收到的数据大于0{recv_buf[recv_len] = '\0'; //添加结束符cout<<"客户端端口号port= "<<ntohs(cliaddr.sin_port)<<endl;cout<<"客户端ip= "<<inet_ntoa(cliaddr.sin_addr)<<endl;printf("从客户端接收到 %d 个数据,数据是:%s\r\n",recv_len,recv_buf); //打印出接收到的数据memset(recv_buf,0,sizeof(recv_buf));}//4.使用sendto函数发生数据address_len = sizeof(struct sockaddr); //地址长度strcpy(send_buf,"hello client!");send_len = sendto(sockfd, send_buf, strlen(send_buf), 0,(const struct sockaddr *)&cliaddr, address_len);if(send_len > 0){cout<<"发送了 "<<send_len<<" 个数据"<<endl;memset(send_buf,0,sizeof(send_buf)); //清空接收缓存区}}cout<<"关闭连接并退出"<<endl;close(sockfd); //关闭socket文件描述符return 0;
}
2.client端程序实现(udp_client.cpp)
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <string.h>
#include <iostream>using namespace std; //使用标准空间//在使用UDP网络编程的时候,由于UDP非面向连接。因此可以简单总结UDP client端的程序编写流程如下:
//1.socket创建fd
//2.确定server的socket信息并写入servaddr中
//3.直接调用sendto函数给服务器发送消息,其中要用到servaddr信息
//4.调用recv函数接收来自服务器的消息,(因为客户端知道服务器的信息,因此直接recv就可以,而不用recvfrom)#define SERV_PORT 8010 //服务器端口
#define SERV_ADDR "192.168.1.23" //服务器ip
#define CLI_ADDR "192.168.1.50" //定义客户端地址,一般用不到int main(int argc,char **argv)
{int ret = -1;int sockfd = -1; //定义网络文件描述符int address_len = 0; //目的的长度struct sockaddr_in servaddr={0}; //用来存放服务器的socket相关信息int send_len; //发送数据长度int recv_len; //接收数据长度char recv_buf[1000]; //定义接收缓存区char send_buf[1000]; //定义发送缓存区//1.首先使用socket函数创建网络文件描述符(类似于文件IO中的open函数)//函数原型:int socket(int domain, int type, int protocol); sockfd = socket(AF_INET, SOCK_DGRAM, 0); //ipv4,UDP,系统自动选择protocolif(sockfd < 0){cout<<"创建socket文件描述符失败"<<endl;_exit(-1);}cout<<"sockfd="<<sockfd<<endl;//2.然后确定server的socket信息并写入servaddr中servaddr.sin_family = AF_INET; //定义servaddr的domain地址族为ipv4servaddr.sin_port = htons(SERV_PORT); //定义servaddr的portnum为SERV_PORT(8010),host to net shortservaddr.sin_addr.s_addr = inet_addr(SERV_ADDR); //定义servaddr的address为SERV_ADDR(192.168.1.23) person----->u32//下面客户端和服务器互相收发while(1){cout<<"请输入要发送给服务器的内容:";cin >> send_buf;if(!strncmp(send_buf,"+++",3))break;//3.使用sendto函数给服务器发生数据//入口参数:fd,send_buf,send_len,flag,server_addr,server_lenaddress_len = sizeof(struct sockaddr); //地址长度send_len = sendto(sockfd, send_buf, strlen(send_buf), 0,(const struct sockaddr *)&servaddr, address_len);if(send_len > 0){cout<<"发送了 "<<send_len<<" 个数据"<<endl;memset(send_buf,0,sizeof(send_buf)); //清空接收缓存区}//4.使用recv函数接收来自服务器的数据ret = recv(sockfd, recv_buf, sizeof(recv_buf), 0); //接收客户端发送来的数据,注意此处使用的网络描述符是clifdif(ret < 1){cout<<"服务器断开了连接"<<endl;break;}cout<<"收到服务器发送的数据:len= "<<ret<<" buf= "<<recv_buf<<endl;memset(recv_buf,0,sizeof(recv_buf)); //清空接收缓存区}cout<<"关闭连接并退出"<<endl; //实际从未建立过连接close(sockfd); //关闭socket文件描述符return 0;
}
3.编译与执行
g++ udp_server.cpp -o server
g++ udp_client.cpp -o client
#arm-linux-gnueabihf-g++ udp_server.cpp -o server
#arm-linux-gnueabihf-g++ udp_client.cpp -o client
其中g++编译器编译出的文件在x86架构处理器运行,arm-linux-gnueabihf-g++编译出的文件在ARM架构处理器运行。另注意用到多线程pthread时编译需要链接pthread库。
执行说明,由于UDP不面向连接,因此接收和发送的时候都需要知道对方的信息,而服务器可以接收多个客户端的数据,因此在执行测试时可以打开一个server程序和多个client程序,建立一对多的连接,且彼此之间交互互不影响。
C语言实现socket网络编程及多线程编程相关推荐
- Java基础了解-12-网络编程/发送邮件/多线程编程/Applet 基础/文档注释
@ 网络编程/发送邮件/多线程编程/Applet 基础/文档注释 一.Java 网络编程 网络编程是指编写运行在多个设备(计算机)的程序,这些设备都通过网络连接起来. java.net 包中 J2SE ...
- 响应式编程(反应式编程)的来龙去脉(同步编程、多线程编程、异步编程再到响应式编程)
响应式编程的来龙去脉(同步编程.多线程编程.异步编程再到响应式编程) 文章目录 响应式编程的来龙去脉(同步编程.多线程编程.异步编程再到响应式编程) 简介 1. 示例 2. 同步编程 3. 多线程编程 ...
- 【socket】C语言的Socket网络编程
目录 Socket网络编程 1.网络知识 网络中进程之间如何通信? 什么是Socket? socket一词的起源 怎么理解端口? 怎么理解socket ? 2. 客户/服务器模式 2.1 服务器端: ...
- 异步编程之异步编程与多线程编程的联系和区别
1.异步编程与多线程的区别 共同点:异步和多线程两者都可以达到避免调用线程阻塞的目的,从而提高软件的可响应性 不同点: (1)线程不是一个计算机硬件的功能,而是操作系统提供的一种逻辑功能,线程本质上是 ...
- 异步编程与多线程编程的联系和区别
1.异步编程与多线程的区别 共同点:异步和多线程两者都可以达到避免调用线程阻塞的目的,从而提高软件的可响应性 不同点: (1)线程不是一个计算机硬件的功能,而是操作系统提供的一种逻辑功能,线程本质上是 ...
- python多线程编程_python多线程编程(1): python对多线程的支持
前面介绍过多线程的基本概念,理解了这些基本概念,掌握python多线程编程就比较容易了. 在开始之前,首先要了解一下python对多线程的支持. 虚拟机层面 Python虚拟机使用GIL(Global ...
- 多线程编程java_Java多线程编程
Java给多线程编程提供了内置的支持.一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务. 多线程是多任务的一种特别的形式,但多线程使用了更小的资源开销. ...
- java多线程编程_Java多线程编程实战指南+设计模式篇.pdf
Java多线程编程实战指南+设计模式篇.pdf 对Java架构技术感兴趣的工程师朋友们可以关注我,转发此文后私信我"Java"获取更多Java编程PDF资料(附送视频精讲) 关注我 ...
- java多线程编程_Java多线程编程
本文主要对Java多线程编程进行深入研究.本文通过查看源代码及参考资料等方式研究.参考文章: Java多线程编程深入详解. 由问题入手: 问题1: 2种创建Thread的方式都是实现run()方法,但 ...
- Java多线程编程(2)--多线程编程中的挑战
一.串行.并发和并行 为了更清楚地解释这三个概念,我们来举一个例子.假设我们有A.B.C三项工作要做,那么我们有以下三种方式来完成这些工作: 第一种方式,先开始做工作A,完成之后再开始做工作B ...
最新文章
- 【Swift】变量/常量/类型总结
- android fragment 弹出对话框,Android DialogFragment弹框实现
- Socket发完消息后,立即关闭连接,客户端丢失数据的问题
- Sqoop 同步数据到mysql, Can't parse input data: '\N'
- thinkphp与php共享session
- 教你玩转CSS表格(table)
- 1748. The Most Complex Number/LG的数学计划~~~持续更新ing(反素数求解)
- mysql int(3)_MySQL中int(11)与int(3)的区别_MySQL
- dubbo项目引用另一个项目的接口
- php与bootstrap
- 人民币决定页游未来——8166网页游戏行业分析
- PHP正则JSESSIONID,会话状态保持,JSESSIONID,COOKIE,URL重写
- iOS转前端之仿写宠物网(适配不同尺寸)
- RoaringBitmap数据结构以及精确去重UDAF实现
- 2021-10-18记录 MediaTek MT7620A 平台对应的类型
- IOS苹果ipa重签名工具(苹果签名工具,ios签名工具,支持Windows系统和Macos系统)
- GPA——平均绩点计算器(5.0分制)
- Mysql 安装,及其闪退的问题解决
- 怎么把歌曲导入备忘录里
- DNS对网络连通性的影响