0

我正在用 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;
}
4

2 回答 2

4

两个错误:

  1. 你投的太多了,这里唯一的地方应该是 inaddr 的东西。
  2. 你没有听你的编译器,提高警告级别。

现在,问题(或者可能只是一个?)实际上是这样的:

pthread_create(&pth,NULL,threadFunc(newsockfd),(void*) &i);

这将调用threadFunc(newsockfd)并将结果传递给 pthread_create。但是,第二部分永远不会发生,因为该函数调用 pthread_exit 或从末尾落下而没有返回任何内容,这可能会导致任何事情发生。

于 2013-02-10T17:30:11.980 回答
0

您的服务器代码没有可靠地显示 printf 语句是因为您没有以“\n”结束传递给 printf 的字符串。

更改所有 printf 语句以包含尾随 \n 以便立即“刷新”输出。例如

代替:

printf("after pthread create");

做这个:

printf("after pthread create\n");

对所有printf 语句重复该修复。然后,当客户端连接到它时,程序流将更容易看到。

您的代码中可能还有大约 5 或 6 个其他错误。我要说的主要是因为客户端发送了 4 个字节的“EXIT”,这并不意味着 TCP 流不会在两个单独的读取调用中将其分段为“EX”和“IT”,具体取决于管间状态。始终编​​写您的协议代码,就好像 read/recv 一次只返回一个字符一样。或者只是将 MSG_WAITALL 与 recv() 一起使用,以便您始终读取块大小。

于 2013-02-10T12:30:24.113 回答