我正在研究在C中实现多线程多客户端单服务器套接字。但是无论出于何种原因,当前程序使用pthread_create()创建新线程时,它都不会超过该行代码。我已经在这行代码之前和之后放置了打印行,所有打印行在手工打印之前都很好,但是在打印之后都没有。这让我相信pthread_create()在某种程度上是错误的。这个奇怪的是我可以有1个客户端连接并成功从服务器发送/接收数据但是因为listen()命令所在的循环没有推进我不能承担额外的客户端。感谢你对此事的帮助。
服务器代码
#include <stdio.h>
#include <stdlib.h> //for IOs
#include <string.h>
#include <unistd.h>
#include <sys/types.h> //for system calls
#include <sys/socket.h> //for sockets
#include <netinet/in.h> //for internet
#include <pthread.h>
void error(const char *msg)
{
perror(msg);
exit(1);
}
void *threadFunc(int mySockFd)
{
int n;
char buffer[256];
do
{
bzero(buffer,256);
n = read(mySockFd,buffer,255);
if (n < 0)
{
error("ERROR reading from socket");
}
else if(strcmp(buffer, "EXIT\n") == 0)
{
printf("Exit by user\n");
pthread_exit(NULL);
}
else
{
printf("Here is the message: %s\n",buffer);
n = write(mySockFd,"I got your message",18);
if (n < 0)
{
error("ERROR writing to socket");
}
}
}while(n >= 0);
}
int main(int argc, char *argv[])
{
int sockfd;
int newsockfd;
int portno;
pthread_t pth;
int n; /*n is the return value for the read() and write() calls; i.e. it contains the number of characters read or written.*/
int i = 0;
printf("after var decl");
socklen_t clilen; /*clilen stores the size of the address of the client. This is needed for the accept system call.*/
char buffer[256]; /*The server reads characters from the socket connection into this buffer.*/
struct sockaddr_in serv_addr;
struct sockaddr_in cli_addr;
if (argc < 2)
{
fprintf(stderr,"ERROR, no port provided\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
error("ERROR opening socket");
}
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
{
error("ERROR on binding");
}
do
{
printf("before listen");
listen(sockfd,5);
printf("after listen");
clilen = sizeof(cli_addr);
printf("before accept");
newsockfd = accept(sockfd,(struct sockaddr *) &cli_addr,&clilen);
printf("after accept");
pthread_create(&pth,NULL,threadFunc(newsockfd),(void*) &i);
printf("after pthread create");
if (newsockfd < 0)
{
error("ERROR on accept");
}
}while(1 == 1);
bzero(buffer,256);
n = read(newsockfd,buffer,255);
if (n < 0)
{
error("ERROR reading from socket");
}
printf("Here is the message: %s\n",buffer);
if (n < 0) error("ERROR writing to socket");
close(newsockfd);
close(sockfd);
return 0;
这是客户端代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h> /*The file netdb.h defines the structure hostent, which will be used below.*/
void error(const char *msg)
{
perror(msg);
exit(0);
}
int main(int argc, char *argv[])
{
int sockfd;
int portno;
int n;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[256];
if (argc < 3)
{
fprintf(stderr,"usage %s hostname port\n", argv[0]);
exit(0);
}
portno = atoi(argv[2]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
error("ERROR opening socket");
}
server = gethostbyname(argv[1]);
if (server == NULL)
{
fprintf(stderr,"ERROR, no such host\n");
exit(0);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,
server->h_length);
serv_addr.sin_port = htons(portno);
if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0)
{
error("ERROR connecting");
}
do
{
printf("Please enter the message: ");
bzero(buffer,256);
fgets(buffer,255,stdin);
n = write(sockfd,buffer,strlen(buffer));
if(strcmp(buffer,"EXIT\n") == 0)
{
printf("Connection Terminated\n");
break;
}
if (n < 0)
{
error("ERROR writing to socket");
}
bzero(buffer,256);
n = read(sockfd,buffer,255);
printf("%s\n",buffer);
if (n < 0)
{
error("ERROR reading from socket");
printf("%s\n",buffer);
}
}while(1 == 1);
close(sockfd);
return 0;
}
答案 0 :(得分:4)
两个错误:
现在,问题(或者只是一个?)实际上是这样的:
pthread_create(&pth,NULL,threadFunc(newsockfd),(void*) &i);
这将调用threadFunc(newsockfd)
并将结果传递给pthread_create。第二部分永远不会发生,因为该函数调用pthread_exit或在不返回任何内容的情况下掉线,这可能导致任何事情发生。
答案 1 :(得分:0)
您的服务器代码未正确显示printf语句是因为您没有以“\ n”结束传递给printf的字符串。
更改所有printf语句以包含尾随\ n,以便立即“刷新”输出。 E.g。
而不是:
printf("after pthread create");
这样做:
printf("after pthread create\n");
对printf语句的所有重复此修复。然后,当客户端连接到程序流时,程序流将更容易看到。
您的代码中可能还有大约5或6个其他错误。我想要调用的主要原因是客户端发送了4个字节的“EXIT”,并不意味着TCP流不会在两个单独的读取调用中将其分段为“EX”和“IT”,具体取决于intertubes的状态。始终编写协议代码,就好像read / recv一次只返回一个char。 OR 只需将MSG_WAITALL与recv()一起使用,以便始终读取块大小。