以下循环位于程序主体内部。它接受传入连接,并且有一个线程可以使用它。
问题是,一旦任何线程终止,它就会终止整个程序。这是代码:
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <pthread.h>
#define BUFLEN 1500
#define MAXCON 30
char *returnTimeDate(int inputchoice);
void readWriteToClient(int inputconnfd);
int main(){
int backlog = 10;
int fd;
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd == -1) {
// Error: unable to create socket
}
struct sockaddr_in cliaddr;
socklen_t cliaddrlen = sizeof(cliaddr);
struct sockaddr_in addr;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_family = AF_INET;
addr.sin_port = htons(5001);
if (bind(fd, (struct sockaddr *) &addr, (socklen_t) sizeof(addr)) == -1) {
fprintf(stderr,"Bind Didn't Work\n");
}
if (listen(fd, backlog) == -1) {
fprintf(stderr,"Listen Didn't Work\n");
}
pthread_t *threadsArray = (pthread_t *)calloc(MAXCON, sizeof(pthread_t));
pthread_t *threadPtr = threadsArray;
int k;
for(k = 0; k < MAXCON; k++){
fprintf(stderr,"Make %d\n",k);
int connfd;
connfd = accept(fd, (struct sockaddr *) &cliaddr, &cliaddrlen);
if (connfd == -1) {
fprintf(stderr,"Accept Didn't Work\n");
}
fprintf(stderr,"Waited\n",k);
pthread_create( &threadPtr, NULL, readWriteToClient, (void *)connfd);
threadPtr++;
}
pthread_t *threadPtrJoin = threadsArray;
for(k = 0; k < MAXCON; k++){
fprintf(stderr,"Join %d\n",k);
pthread_join( *threadPtrJoin, NULL);
threadPtrJoin++;
}
/* readWriteToClient(connfd);*/
close(fd);
return 0;
}
void readWriteToClient(int inputconnfd){
int connfd = inputconnfd;
while(1){
char *dateString = "DATE\r\n";
char *timeString = "TIME\r\n";
char *endString = "end";
char *bufferTime = returnTimeDate(0);
char *bufferDate = returnTimeDate(1);
ssize_t i;
ssize_t rcount;
char buf[BUFLEN];
char *toReturn = (char *)malloc(BUFLEN*sizeof(char));
rcount = read(connfd, buf, BUFLEN);
if((strcmp (buf, dateString)) == 0){
strcpy(toReturn, bufferDate);
}
if((strcmp (buf, timeString)) == 0){
strcpy(toReturn, bufferTime);
}
if((strcmp (buf, endString)) == 0){
goto outside;
}
if (rcount == -1) {
// Error has occurred
printf("Error: rcount -1");
}
/* fprintf(stderr,"I have received = %s\n",buf);*/
if (write(connfd, toReturn, BUFLEN) == -1) {
fprintf(stderr,"I didn't write = %s\n",buf);
}
}
outside: return;
}
char *returnTimeDate(int inputchoice){
time_t timer;
char *bufferTimee = (char *)malloc(25*sizeof(char));
char *bufferDatee = (char *)malloc(25*sizeof(char));
struct tm* tm_info;
time(&timer);
tm_info = localtime(&timer);
strftime(bufferTimee, 25, "%H:%M:%S\n\0", tm_info);
strftime(bufferDatee, 25, "%d:%m:%Y\n\0", tm_info);
if(inputchoice == 0){
return bufferTimee;
}else{
return bufferDatee;
}
}
为什么要这样做?
答案 0 :(得分:4)
使用pthreads时有一些问题非常严重。
首先,我认为你的意思是:
int st = pthread_create(&threadPtr[k], NULL, readWriteToClient, (void *)connfd);
if (st != 0) {
/* handle error */
}
请注意以下事项:
pthread_create()
的返回值存储在st
中并处理其错误情况。 &threadPtr[k]
(pthread_t *
类型),而不是&threadPtr
(类型pthread_t **
)。 这可能是您问题的原因。 但是,我对您的代码的一个主要问题是,您通过将readWriteToClient
传递给pthread_create()
来调用未定义的行为。 pthread_create
原型如下:
int pthread_create(pthread_t *restrict,
const pthread_attr_t *restrict,
void *(*start_routine)(void*),
void *restrict arg);
即使您将&threadPtr
更改为&threadPtr[k]
,也可以按以下方式调用:
int pthread_create(pthread_t *restrict,
const pthread_attr_t *restrict,
void (*start_routine)(int), // oops!
void *restrict arg);
所以,pthread_create()
接受一个指向一种类型函数的指针,但是你传递了一个指向另一种类型函数的指针(C11,6.7.6.3/15,强调我的):
要兼容两种功能类型,两者都应指定兼容的返回类型。 此外,参数类型列表(如果两者都存在)应在数量上一致 参数和省略号终止符的使用; 相应的参数应具备 兼容类型。 [...]
指向该函数的指针是隐式转换的,无论如何都要调用你的函数,但这是非法的,按照标准(C11,6.3.2.3/8,强调我的):
指向一种类型的函数的指针可以转换为指向a的指针 另一种类型的功能又回来了;结果应该比较 等于原始指针。 如果使用转换的指针进行调用 一个类型与引用类型不兼容的函数, 行为未定义。
由于您正在调用未定义的行为,因此无法确定代码执行后的行为方式。
另外,请记住,将int
转换为void *
并返回并不能保证在不丢失信息的情况下(它是实现定义的),所以要小心。
如果在启用警告的情况下进行编译,您应该
>答案 1 :(得分:-1)
我敢打赌你的编译器会对不兼容的指针类型发出警告....
我的建议是在编译阶段修复每个警告。
如果这样做了,你会注意到pthread函数的参数必须是指向void而不是int的指针。
另外,后一个函数必须返回一个指向void的指针,而不仅仅是void,这会导致堆栈混乱。
首先,使用连接fds数组
int connfd[MAXCON];
然后将connfd保存在
中connfd[k] = accept(fd, (struct sockaddr *) &cliaddr, &cliaddrlen);
然后,改变
pthread_create( threadPtr, NULL, readWriteToClient, connfd);
与
pthread_create( threadPtr, NULL, readWriteToClient, (void *) &connfd[k]);
并更改
void readWriteToClient(int inputconnfd)
与
void *readWriteToClient(void *inputconnfd)
然后使用
将其分配给局部变量int connfd = *((int *) inputconnfd);
让我知道它是否有效