文章目录

  • 一.概述
  • 二.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网络编程及多线程编程相关推荐

  1. Java基础了解-12-网络编程/发送邮件/多线程编程/Applet 基础/文档注释

    @ 网络编程/发送邮件/多线程编程/Applet 基础/文档注释 一.Java 网络编程 网络编程是指编写运行在多个设备(计算机)的程序,这些设备都通过网络连接起来. java.net 包中 J2SE ...

  2. 响应式编程(反应式编程)的来龙去脉(同步编程、多线程编程、异步编程再到响应式编程)

    响应式编程的来龙去脉(同步编程.多线程编程.异步编程再到响应式编程) 文章目录 响应式编程的来龙去脉(同步编程.多线程编程.异步编程再到响应式编程) 简介 1. 示例 2. 同步编程 3. 多线程编程 ...

  3. 【socket】C语言的Socket网络编程

    目录 Socket网络编程 1.网络知识 网络中进程之间如何通信? 什么是Socket? socket一词的起源 怎么理解端口? 怎么理解socket ? 2. 客户/服务器模式 2.1 服务器端: ...

  4. 异步编程之异步编程与多线程编程的联系和区别

    1.异步编程与多线程的区别 共同点:异步和多线程两者都可以达到避免调用线程阻塞的目的,从而提高软件的可响应性 不同点: (1)线程不是一个计算机硬件的功能,而是操作系统提供的一种逻辑功能,线程本质上是 ...

  5. 异步编程与多线程编程的联系和区别

    1.异步编程与多线程的区别 共同点:异步和多线程两者都可以达到避免调用线程阻塞的目的,从而提高软件的可响应性 不同点: (1)线程不是一个计算机硬件的功能,而是操作系统提供的一种逻辑功能,线程本质上是 ...

  6. python多线程编程_python多线程编程(1): python对多线程的支持

    前面介绍过多线程的基本概念,理解了这些基本概念,掌握python多线程编程就比较容易了. 在开始之前,首先要了解一下python对多线程的支持. 虚拟机层面 Python虚拟机使用GIL(Global ...

  7. 多线程编程java_Java多线程编程

    Java给多线程编程提供了内置的支持.一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务. 多线程是多任务的一种特别的形式,但多线程使用了更小的资源开销. ...

  8. java多线程编程_Java多线程编程实战指南+设计模式篇.pdf

    Java多线程编程实战指南+设计模式篇.pdf 对Java架构技术感兴趣的工程师朋友们可以关注我,转发此文后私信我"Java"获取更多Java编程PDF资料(附送视频精讲) 关注我 ...

  9. java多线程编程_Java多线程编程

    本文主要对Java多线程编程进行深入研究.本文通过查看源代码及参考资料等方式研究.参考文章: Java多线程编程深入详解. 由问题入手: 问题1: 2种创建Thread的方式都是实现run()方法,但 ...

  10. Java多线程编程(2)--多线程编程中的挑战

    一.串行.并发和并行   为了更清楚地解释这三个概念,我们来举一个例子.假设我们有A.B.C三项工作要做,那么我们有以下三种方式来完成这些工作:   第一种方式,先开始做工作A,完成之后再开始做工作B ...

最新文章

  1. 【Swift】变量/常量/类型总结
  2. android fragment 弹出对话框,Android DialogFragment弹框实现
  3. Socket发完消息后,立即关闭连接,客户端丢失数据的问题
  4. Sqoop 同步数据到mysql, Can't parse input data: '\N'
  5. thinkphp与php共享session
  6. 教你玩转CSS表格(table)
  7. 1748. The Most Complex Number/LG的数学计划~~~持续更新ing(反素数求解)
  8. mysql int(3)_MySQL中int(11)与int(3)的区别_MySQL
  9. dubbo项目引用另一个项目的接口
  10. php与bootstrap
  11. 人民币决定页游未来——8166网页游戏行业分析
  12. PHP正则JSESSIONID,会话状态保持,JSESSIONID,COOKIE,URL重写
  13. iOS转前端之仿写宠物网(适配不同尺寸)
  14. RoaringBitmap数据结构以及精确去重UDAF实现
  15. 2021-10-18记录 MediaTek MT7620A 平台对应的类型
  16. IOS苹果ipa重签名工具(苹果签名工具,ios签名工具,支持Windows系统和Macos系统)
  17. GPA——平均绩点计算器(5.0分制)
  18. Mysql 安装,及其闪退的问题解决
  19. 怎么把歌曲导入备忘录里
  20. DNS对网络连通性的影响

热门文章

  1. Unity学习笔记(一)—— 基础知识
  2. AIX服务(Unix系统)下安装Vim
  3. OneNote 安装代码高亮插件 NoteHightlight的安装及使用基础教程
  4. OpenCL编程入门(一)
  5. OpenCL入门概念
  6. cad墙线打断lisp_autocad 2010怎么打断墙线?
  7. 国科大学习资料--自然语言处理(宗成庆)-2016期末考试题
  8. oracle表空间使用情况查看
  9. 搭建高性能计算环境(九)、应用软件的安装之gaussian 09
  10. 远程办公软件华为云WeLink视频会议指南(下篇:记录会议纪要)