多程序和多執行緒簡單tcp聊天程式
阿新 • • 發佈:2018-12-13
如果需要一個服務端可以連線多個客戶端,並同時與多個(不超多listen第二個引數及最大同時併發數)客戶端通訊,可以利用多程序即建立子程序,子程序來完成服務端的接受和傳送資料;也可以建立多個執行緒。對於tcp一些介面具體使用可以檢視這篇部落格:https://blog.csdn.net/sophia__yu/article/details/82827500 tcp客戶端程式碼
//tcp 客戶端程式碼 //1.建立套接字 //2.繫結地址資訊 //3.向服務端傳送連線請求 //4.傳送資料 //5.接受資料 //6.關閉socket描述符 #include<stdio.h> #include<error.h> #include<arpa/inet.h> #include<netinet/in.h> #include<string.h> #include<sys/socket.h> #include<stdlib.h> int main(int argc,char* argv[]) { if(argc!=3) { printf("Usage ip and port\n"); } //1.建立套接字 int sockfd=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); if(sockfd<0) { perror("socket error"); return -1; } //2.繫結地址資訊(不推薦手動寫繫結資訊程式碼) //3.向服務端傳送連線請求 //int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen); struct sockaddr_in ser_addr; ser_addr.sin_family=AF_INET; ser_addr.sin_port=(htons)(atoi(argv[2])); ser_addr.sin_addr.s_addr=(inet_addr)(argv[1]);//因為argv[]是char*,用atoi使字串轉成整型 int len=sizeof(struct sockaddr_in); int ret=connect(sockfd,(struct sockaddr*)&ser_addr,len); if(ret<0) { perror("connect error"); close(sockfd); return -1; } //連線成功,socket描述符裡有服務端和客戶端IP地址和port while(1) { //4.傳送資料 // ssize_t send(int sockfd, const void *buf, size_t len, int flags); char buff[1024]={0}; printf("please send\n"); scanf("%s",buff); ret=send(sockfd,buff,strlen(buff),0); //預設阻塞接受資料 if(ret<0) { perror("send error"); close(sockfd); return -1; } //5.接受資料 //ssize_t recv(int sockfd, void *buf, size_t len, int flags); memset(buff,0x00,1024); ret=recv(sockfd,buff,1023,0);//預設阻塞接受資料 if(len<0)//小於0接受失敗 { perror("recv error"); close(sockfd); continue; } else if(len==0)//等於0對端將連線斷開 { perror("peer has performed an orderly shutdown"); close(sockfd); continue; } printf("[%s:%d]say:%s\n",(inet_ntoa)(ser_addr.sin_addr),(ntohs)(ser_addr.sin_port),buff); } close(sockfd); return 0; }
多程序服務端程式碼:
//多程序的tcp服務端程式碼 #include<stdio.h> #include<unistd.h> #include<error.h> #include<string.h> #include<sys/socket.h> #include<netinet/in.h> #include<signal.h> #include<wait.h> #include<stdlib.h> #include<arpa/inet.h> void profunc(int sockfd) { int pid=fork(); if(pid<0) { perror("fork error"); close(sockfd); return ; } else if(pid==0){ //子程序 接受資料和傳送資料 while(1){ char buff[1024]={0}; int len=recv(sockfd,buff,1023,0);//阻塞接受資料 if(len<0) { perror("recv error"); close(sockfd); return ; } else if(len==0) { perror("peer shutdown"); close(sockfd); return ; } printf("ser say:%s\n",buff); send(sockfd,"hello",5,0);//服務端預設傳送hello } close(sockfd); } else { //父程序 close(sockfd);//子程序和父程序的sockfd在不同空間,所以如果父程序不對sockfd做什麼,需要關閉,但是父程序最好不對sochfd不做什麼,否則無法區別傳送或接 受資料是父程序還是子程序 } } void sigcb(int signum) { while(waitpid(-1,NULL,WNOHANG)!=0)//沒有子程序退出將返回0,用迴圈是將等待子程序資源回收完畢 { } } int main(int argc,char* argv[]) { signal(SIGCHLD,sigcb);//將SIGCHLD自定義設定為等待子程序退出功能 if(argc!=3) { printf("Usage:./ ip port\n"); } //1.建立套接字 int sockfd=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);//6 if(sockfd<0) { perror("socket error"); return -1; } //2.繫結地址資訊 struct sockaddr_in ser_addr; ser_addr.sin_family=AF_INET; ser_addr.sin_port=htons((atoi)(argv[2])); ser_addr.sin_addr.s_addr=(inet_addr)(argv[1]); int len=sizeof(struct sockaddr_in); int ret=bind(sockfd,(struct sockaddr*)&ser_addr,len); if(ret<0) { perror("bind error"); close(sockfd); return -1; } //3.監聽,listen只是設定好socket的屬性,連線成功佇列最多有5個結點 if(listen(sockfd,5)<0) { perror("losten error"); close(sockfd); return -1; } //4.獲取新連線的客戶端資訊 //多程序,建立子程序,子程序來接受傳送資料,從而實現一個服務端可以同時連線多個客戶端 while(1) { struct sockaddr_in cli_addr; len=sizeof(struct sockaddr_in); int newsockfd=accept(sockfd,(struct sockaddr*)&cli_addr,&len); profunc(newsockfd); } close(sockfd); return 0; }
第一個客戶端: 第二個客戶端: 服務端: 多執行緒tcp服務端程式碼
//多程序的tcp服務端程式碼 #include<stdio.h> #include<unistd.h> #include<error.h> #include<string.h> #include<sys/socket.h> #include<netinet/in.h> #include<signal.h> #include<wait.h> #include<stdlib.h> #include<arpa/inet.h> #include<pthread.h> void* the_start(void* arg) { int sockfd=(int)arg; while(1) { //接受資料 char buff[1024]={0}; int len=recv(sockfd,buff,1023,0);//阻塞接受資料 if(len<0) { perror("recv error"); close(sockfd); return ; } else if(len==0) { perror("peer shutdown"); close(sockfd); return ; } printf("ser say:%s\n",buff); send(sockfd,"hello",5,0);//服務端預設傳送hello } close(sockfd); } int main(int argc,char* argv[]) { if(argc!=3) { printf("Usage:./ ip port\n"); } //1.建立套接字 int sockfd=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);//6 if(sockfd<0) { perror("socket error"); return -1; } //2.繫結地址資訊 struct sockaddr_in ser_addr; ser_addr.sin_family=AF_INET; ser_addr.sin_port=htons((atoi)(argv[2])); ser_addr.sin_addr.s_addr=(inet_addr)(argv[1]); int len=sizeof(struct sockaddr_in); int ret=bind(sockfd,(struct sockaddr*)&ser_addr,len); if(ret<0) { perror("bind error"); close(sockfd); return -1; } //3.監聽,listen只是設定好socket的屬性,連線成功佇列最多有5個結點 if(listen(sockfd,5)<0) { perror("losten error"); close(sockfd); return -1; } //4.獲取新連線的客戶端資訊 //建立多個執行緒 while(1) { struct sockaddr_in cli_addr; len=sizeof(struct sockaddr_in); int newsockfd=accept(sockfd,(struct sockaddr*)&cli_addr,&len); //建立執行緒 // // int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); pthread_t tid; int ret; ret=pthread_create(&tid,NULL,the_start,(void*)newsockfd); } close(sockfd); return 0; }
第一個客戶端: 第二個客戶端: 服務端: