@使用多线程在CentOS里编写类似QQ的聊天程序
说明一下编写的思路和流程
首先我们要知道TCP/IP协议在liunx下的操作流程(这部分书上或者网上一堆)。其次,还要知道有socket里有多少函数能阻塞线程。这部分很重要,笔者在写的时候就被这些忽悠了遍。
本次程序使用到带有阻塞的函数
1、连接时阻塞线程的函数:accpet();
原型:SOCKET accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
2、读取时阻塞函数:recv()
原型: int recv(int new_fd, void *buf, int len, unsigned int flags);
第一参数:accpet返回的值
第二参数:缓冲区
第三参数:缓冲区长度
第四参数:一般为0
本次试验主要的线程函数
其实也没有什么特殊的就是pthread_create()
原型:int pthread_create((pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *), void *arg)
第一参数:pthread_t 类型的变量
第二参数:一般UNLL表示手动结束
第三参数:方法指针
第四参数:传递给方法的参数
第四参数很重要,我没有仔细看文档踩了很多雷。
*编写思路
不多说上图
服务器端主要思路是利用accpet()和recv()函数本身自带的阻塞去控制线程的创建和消息的发送。
客户端
主要的想法是,分别利用两个阻塞控制用户端的显示。同时,使用延时,保证两个线程正常显示,给用户好的使用体验。
代码
service.c
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<sys/socket.h>
#include<sys/wait.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<pthread.h>
#define MAXBUF 1024
void* conClient(void* fd);
void *recvClient(void *fd);
static char buf[MAXBUF+1];
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int main(int argc,char *argv[])
{
socklen_t len;
int pid;
int sockfd,new_fd;
struct sockaddr_in my_addr,their_addr;
unsigned int myport,lisnum;
//char buf[MAXBUF+1];
if(argv[2])
myport=atoi(argv[2]);
else
myport=8088;
if(argv[3])
lisnum=atoi(argv[3]);
else
lisnum=5;
if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
{
perror("socket");
exit(EXIT_FAILURE);
}
bzero(&my_addr,sizeof(my_addr));
my_addr.sin_family=AF_INET;
my_addr.sin_port=htons(myport);
if(argv[1])
my_addr.sin_addr.s_addr=inet_addr(argv[1]);
else
my_addr.sin_addr.s_addr=INADDR_ANY;
if(bind(sockfd,(struct sockaddr *)&my_addr,sizeof(struct sockaddr))==-1)
{
perror("bind");
exit(EXIT_FAILURE);
}
if(listen(sockfd,lisnum)==-1)
{
perror("listen");
exit(EXIT_FAILURE);
}
while(1)
{
//sleep(500);
pthread_t con;
printf("wait for connect!\n");
len=sizeof(struct sockaddr);
new_fd=accept(sockfd,(struct sockaddr *)&their_addr,&len);
printf("accept true new_fd:%d\n\n",new_fd);
int k;
printf("server:got connection from %s,port %d,socket %d\n",inet_ntoa(their_addr.sin_addr),ntohs(their_addr.sin_port),new_fd);
k = pthread_create(&con, NULL, conClient, (void*)new_fd);
printf("%d\n",k);
printf("newfd=%d\n",new_fd);
}
close(sockfd);
}
void *conClient(void* fd){
int new_fd = (int)fd;
char* buf1 = "wlecome Like QQ";
// char buf[1024];
strcpy(buf,buf1);
pthread_detach(pthread_self());
int len;
pthread_t con;
pthread_create(&con,NULL,recvClient,(void*)new_fd);
while(1)
{
printf("wait\n");
len=recv(new_fd,buf,strlen(buf),0);
printf("message:%s\t recv sucessful,send %dbyte!\n",buf,len);
if(len < 0)
{
break;
}
}
close(new_fd);
pthread_exit(NULL);
}
void *recvClient(void * fd)
{
int len;
int new_fd = (int)fd;
while(1)
{
//printf("len : %d",strlen(buf));
if(strlen(buf) > 0)
{
len=send(new_fd,buf,sizeof(buf),0);
printf("send message: %S len : %d",buf,len);
sleep(1);
bzero(buf,strlen(buf));
}
}
close(new_fd);
pthread_exit(NULL);
}
client.c
#include<stdio.h>
#include<string.h>
#include<errno.h>
#include<sys/socket.h>
#include<resolv.h>
#include<stdlib.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#define MAXBUF 1024
void* recv_client(void * fd);
int main(int argc,char **argv)
{
int sockfd,len;
struct sockaddr_in dest;
char buffer[MAXBUF+1];
char sendbuf[MAXBUF+1];
if(argc!=3)
{
printf("error format,it must be:\n\t\t%s IP port\n",argv[0]);
exit(EXIT_FAILURE);
}
if((sockfd=socket(AF_INET,SOCK_STREAM,0))<0)
{
perror("Socket");
exit(errno);
}
printf("socket created\n");
bzero(&dest,sizeof(dest));
dest.sin_family=AF_INET;
dest.sin_port=htons(atoi(argv[2]));
if(inet_aton(argv[1],(struct in_addr *)&dest.sin_addr.s_addr)==0)
{
perror(argv[1]);
exit(errno);
}
if(connect(sockfd,(struct sockaddr *)&dest,sizeof(dest))==-1)
{
perror("Connect");
exit(errno);
}
printf("server connected\n");
pthread_t tid;
int ret;
ret = pthread_create(&tid,NULL,recv_client,(void *)sockfd);
if(0 > ret)
{
perror("pthread_create");
return -1;
}
sleep(1);
while(1)
{
bzero(sendbuf,MAXBUF+1);
printf("pls send message to send:");
fgets(sendbuf,MAXBUF,stdin);
if(!strncasecmp(sendbuf,"quit",4))
{
printf("i will quit!\n");
break;
}
len=send(sockfd,sendbuf,strlen(sendbuf)-1,0);
if(len<0)
{
printf("message '%s' send failure,errno code is %d,errno message is '%s'\n",buffer,errno,strerror(errno));
break;
}
else
{
sleep(1);
}
}
close(sockfd);
return 0;
}
void * recv_client(void* fd)
{
char recvbuf[1024];
int sockfd = (int)fd;
while(1)
{
int ret = recv(sockfd,recvbuf,sizeof(recvbuf),0);
if(0 > ret)
{
perror("recv");
return;
}
printf("\nmessage from server: %s\n",recvbuf);
// printf("\npls send message to send:");
bzero(recvbuf,1025);
}
}
代码效果图
结语
本次第一次在liunx上做一些程序,这是我们的作业。有不好的地方希望指正。
参考链接
https://www.cnblogs.com/gildoringlorin/p/3949765.html