- 并發(fā)概念:
- 并發(fā)是指兩個(gè)或多個(gè)事件在
同一時(shí)間間隔
發(fā)生; - 多線程實(shí)現(xiàn)TCP并發(fā)服務(wù)器的實(shí)現(xiàn)流程:
- 一、創(chuàng)建套接字(socket函數(shù)):
- 通信域選擇IPV4網(wǎng)絡(luò)協(xié)議、套接字類型選擇流式;
int sockfd = socket(AF_INET,SOCK_STREAM,0); //通信域選擇IPV4、套接字類型選擇流式
- 二、填充服務(wù)器的網(wǎng)絡(luò)信息結(jié)構(gòu)體:
- 1.定義網(wǎng)絡(luò)信息結(jié)構(gòu)體變量;
- 2.求出結(jié)構(gòu)體變量的內(nèi)存空間大??;
- 3.結(jié)構(gòu)體清零;
- 4.使用IPV4網(wǎng)絡(luò)協(xié)議;
- 5.預(yù)留給在終端輸入的IP地址;
- 6.預(yù)留給在終端輸入的網(wǎng)絡(luò)字節(jié)序的端口號(hào);
struct sockaddr_in serveraddr; //定義網(wǎng)絡(luò)信息結(jié)構(gòu)體變量
socklen_t serveraddrlen = sizeof(serveraddr);//求出結(jié)構(gòu)體變量的內(nèi)存空間大小
memset(&serveraddr,0,serveraddrlen); //結(jié)構(gòu)體清零
serveraddr.sin_family = AF_INET; //使用IPV4網(wǎng)絡(luò)協(xié)議
serveraddr.sin_addr.s_addr = inet_addr(argv[1]); //IP地址
serveraddr.sin_port = htons(atoi(argv[2]));//網(wǎng)絡(luò)字節(jié)序的端口號(hào)
- 三、套接字和服務(wù)器的網(wǎng)絡(luò)信息結(jié)構(gòu)體進(jìn)行綁定(bind函數(shù)):
int ret = bind(sockfd,(struct sockaddr *)&serveraddr,serveraddrlen);
- 四、套接字設(shè)置成被動(dòng)監(jiān)聽(tīng)(listen函數(shù)):
int ret1 = listen(sockfd, 5);
- 五、阻塞等待客戶端的連接(accept函數(shù)):
if(-1 == (info.accept_fd = accept(sockfd,(struct sockaddr *)&(info.clientaddr),&clientaddr_len)))
{
perror("accept error");
exit(-1);
}
- 六、若有客戶端連接成功,就創(chuàng)建線程,專門用來(lái)和該客戶端通信(pthread_create函數(shù)):
if(0 != (ret1 = pthread_create(&thread_id,NULL,message_handling,&info)))
{
printf("pthread_create error : errno = [%d] errstr = [%s]\n",ret1,strerror(ret1));
exit(EXIT_FAILURE);
}
- 七、將線程設(shè)置成分離屬性,線程結(jié)束后由操作系統(tǒng)回收資源(pthread_detach函數(shù)):
if(0 != (ret2 = pthread_detach(thread_id)))
{
printf("pthread_create error : errno = [%d] errstr = [%s]\n",ret2,strerror(ret2));
exit(EXIT_FAILURE);
}
- 八、創(chuàng)建線程處理函數(shù)用來(lái)接收來(lái)自客戶端的數(shù)據(jù)(recv函數(shù))和給客戶端發(fā)送應(yīng)答消息(send函數(shù)):
//線程處理函數(shù)
void *message_handling(void *arg);
int nbytes = recv(acceptfd,buf,sizeof(buf),0);
printf("客戶端發(fā)來(lái)數(shù)據(jù)[%s]\n",buf);
strcat(buf,"----k"); //組裝應(yīng)答消息
int ret2 = send(acceptfd,buf,sizeof(buf),0);
- 九、退出線程(pthread_exit函數(shù))和關(guān)閉套接字(close函數(shù)):
close(info.accept_fd);
pthread_exit(NULL);
- 綜合應(yīng)用實(shí)例代碼如下所示:
//多線程實(shí)現(xiàn)TCP并發(fā)服務(wù)器
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <pthread.h>
#include <stdbool.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <unistd.h>
typedef struct INFO
{
int accept_fd;
struct sockaddr_in clientaddr;
}info_t;
//線程處理函數(shù)
void *message_handling(void *arg);
int main(int argc, char const *argv[])
{
//入?yún)⒑侠硇詸z查
if(3 != argc)
{
printf("Usage : %s <IP> <PORT>\n",argv[0]);
exit(-1);
}
//創(chuàng)建套接字
int sockfd = socket(AF_INET,SOCK_STREAM,0);
if(-1 == sockfd)
{
perror("socket error");
exit(-1);
}
//填充服務(wù)器網(wǎng)絡(luò)信息結(jié)構(gòu)體
struct sockaddr_in serveraddr;
socklen_t serveraddr_len = sizeof(serveraddr);
memset(&serveraddr,0,serveraddr_len);
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
serveraddr.sin_port = htons(atoi(argv[2]));
//將套接字與服務(wù)器網(wǎng)絡(luò)信息結(jié)構(gòu)體綁定
if(-1 == bind(sockfd,(struct sockaddr *)&serveraddr,serveraddr_len))
{
perror("bind error");
exit(-1);
}
//將套接字設(shè)置成被監(jiān)聽(tīng)狀態(tài)
if(-1 == listen(sockfd,5))
{
perror("listen error");
exit(-1);
}
info_t info;
pthread_t thread_id;
int ret1 = 0;
int ret2 = 0;
socklen_t clientaddr_len = sizeof(info.clientaddr);
while(true)
{
//等待客戶端連接
if(-1 == (info.accept_fd = accept(sockfd,(struct sockaddr *)&(info.clientaddr),&clientaddr_len)))
{
perror("accept error");
exit(-1);
}
//若有客戶端連接成功,就創(chuàng)建線程,專門用來(lái)和該客戶端通信
if(0 != (ret1 = pthread_create(&thread_id,NULL,message_handling,&info)))
{
printf("pthread_create error : errno = [%d] errstr = [%s]\n",ret1,strerror(ret1));
exit(EXIT_FAILURE);
}
//將線程設(shè)置成分離屬性,線程結(jié)束后由操作系統(tǒng)回收資源
if(0 != (ret2 = pthread_detach(thread_id)))
{
printf("pthread_create error : errno = [%d] errstr = [%s]\n",ret2,strerror(ret2));
exit(EXIT_FAILURE);
}
}
close(sockfd);
return 0;
}
void *message_handling(void *arg)
{
info_t info = *(info_t *)arg;
printf("客戶端[%s : %d]連接到服務(wù)器\n",inet_ntoa(info.clientaddr.sin_addr),ntohs(info.clientaddr.sin_port));
//接收客戶端數(shù)據(jù),并作出應(yīng)答
int nbytes = 0;
char buf[128] = {0};
while(true)
{
memset(buf,0,sizeof(buf));
//接收消息
if(-1 == (nbytes = recv(info.accept_fd,buf,sizeof(buf),0)))
{
perror("recv error");
break;
}else if(0 == nbytes){
printf("客戶端[%s : %d]斷開(kāi)了連接\n",inet_ntoa(info.clientaddr.sin_addr),ntohs(info.clientaddr.sin_port));
break;
}
if(!strcmp(buf,"quit"))
{
printf("客戶端[%s : %d]退出了\n",inet_ntoa(info.clientaddr.sin_addr),ntohs(info.clientaddr.sin_port));
break;
}
printf("客戶端[%s : %d]發(fā)來(lái)消息[%s]\n",inet_ntoa(info.clientaddr.sin_addr),ntohs(info.clientaddr.sin_port),buf);
//組裝應(yīng)答
strcat(buf,"------k");
//發(fā)送應(yīng)答
if(-1 == send(info.accept_fd,buf,sizeof(buf),0))
{
perror("send error");
break;
}
}
close(info.accept_fd);
pthread_exit(NULL);
}
- 本示例代碼,僅供參考;
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-734886.html
文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-734886.html
到了這里,關(guān)于C/S架構(gòu)學(xué)習(xí)之多線程實(shí)現(xiàn)TCP并發(fā)服務(wù)器的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!