/x86_64-linux-gnu/Scrt1.o: В функции `_start': (.text+0x20): неопределенная ссылка на `main'

.. когда я бегу:

gcc -o сервер -lpthread server.c

ошибка произошла. и:

gcc -o клиент -lpthread client.c

опять та же ошибка.

Я пишу программу чата на основе TCP。

Есть server.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
int sockfd;//客户端socket
char* IP = "192.168.255.255";//服务器的IP
short PORT = 8000;//服务器服务端口
typedef struct sockaddr SA;
char name[30];
void init(){
    sockfd = socket(PF_INET,SOCK_STREAM,0);
    struct sockaddr_in addr;//服务器端
    addr.sin_family = PF_INET;
    addr.sin_port = htons(PORT);
    addr.sin_addr.s_addr = inet_addr(IP);
    if (connect(sockfd,(SA*)&addr,sizeof(addr)) == -1){
        perror("无法连接到服务器");
        exit(-1);
    }
    printf("客户端启动成功\n");
}
void start(){
    pthread_t id;
    void* recv_thread(void*);//声明了一个空指针
    pthread_create(&id,0,recv_thread,0);
    char buf2[100] = {};
    sprintf(buf2,"%s进入了聊天室",name);
    send(sockfd,buf2,strlen(buf2),0);
    while(1){
        char buf[100] = {};
        scanf("%s",buf);//消息内容
        char msg[131] = {};
        sprintf(msg,"%s:%s",name,buf);
        send(sockfd,msg,strlen(msg),0);
        if (strcmp(buf,"bye") == 0){//strcmp :字符串比较函数
            memset(buf2,0,sizeof(buf2));//void *memset(void *__s, int __c, size_t __n),复制字符 c(一个无符号字符)到参数 str 所指向的字符串的前 n 个字符。
            sprintf(buf2,"%s退出了聊天室",name);
            send(sockfd,buf2,strlen(buf2),0);
            break;
        }
    }
    close(sockfd);
}
void* recv_thread(void* p){
    while(1){
        char buf[100] = {};
        if (recv(sockfd,buf,sizeof(buf),0) <= 0){
            return 0;
        }
        printf("%s\n",buf);
    }
}
int main(){
    init();
    printf("请输入您的名字:");
    scanf("%s",name);
    start();
    return 0;
}

Я действительно не знаю, что случилось.

Меня это так долго смущает!!! Помоги мне, пожалуйста!!!


person jessic wang    schedule 19.04.2020    source источник
comment
Кроме того, обычное дело: неспособность правильно и полностью обработать результаты, возвращаемые системными вызовами, такими как send(), recv(). Неправильное использование библиотечных вызовов, для которых требуется массив символов с нулевым завершением.   -  person Martin James    schedule 19.04.2020
comment
int main (int argc, char* argv[]) — это общий заголовок основной функции в C.   -  person Gewure    schedule 20.04.2020


Ответы (2)


Порядок имеет значение используйте

gcc -o server server.c -lpthread
person David Ranieri    schedule 19.04.2020
comment
Кажется, это не суть проблемы, все равно выдает ту же ошибку.... - person jessic wang; 20.04.2020

Я нашел решение проблемы, которое, кажется, связано со спецификацией кода. Когда я добавляю пустые строки между всеми определенными функциями (включая основную функцию, конечно), я думаю, что это должно быть ключом к проблеме. Помогите gcc найти точное определение функции main) и снова скомпилируйте ссылку. Новая версия server.c (просто добавьте пустую строку):

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <pthread.h>

int sockfd;//服务器socket
int fds[100];//客户端的socketfd,100个元素,fds[0]~fds[99]
int size =100 ;//用来控制进入聊天室的人数为100以内
char* IP = "192.168.255.255";
short PORT = 8000;
typedef struct sockaddr SA;

int pthread_create(
                 pthread_t *restrict tidp,   //新创建的线程ID指向的内存单元。
                 const pthread_attr_t *restrict attr,  //线程属性,默认为NULL
                 void *(*start_rtn)(void *), //新创建的线程从start_rtn函数的地址开始运行
                 void *restrict arg //默认为NULL。若上述函数需要参数,将参数放入结构中并将地址作为arg传入。
                  );

void init(){
    sockfd = socket(PF_INET,SOCK_STREAM,0);
    if (sockfd == -1){
        perror("创建socket失败");
        exit(-1);
    }
    struct sockaddr_in addr;
    addr.sin_family = PF_INET;
    addr.sin_port = htons(PORT);
    addr.sin_addr.s_addr = inet_addr(IP);
    if (bind(sockfd,(SA*)&addr,sizeof(addr)) == -1){
        perror("绑定失败");
        exit(-1);
    }
    if (listen(sockfd,100) == -1){
        perror("设置监听失败");
        exit(-1);
    }
}

void SendMsgToAll(char* msg){
    int i;
    for (i = 0;i < size;i++){
        if (fds[i] != 0){
            printf("sendto%d\n",fds[i]);
            send(fds[i],msg,strlen(msg),0);
        }
    }
}

void* service_thread(void* p){
    int fd = *(int*)p;
    printf("pthread = %d\n",fd);
    while(1){
        char buf[100] = {};
        if (recv(fd,buf,sizeof(buf),0) <= 0){//阻塞与非阻塞recv返回值没有区分,都是 <0 出错 =0 连接关闭 >0 接收到数据大小
            int i;
            for (i = 0;i < size;i++){
                if (fd == fds[i]){//遍历寻找那个关闭的连接
                    fds[i] = 0;
                    break;
                }
            }
                printf("退出:fd = %dquit\n",fd);
                pthread_exit((void*)&i);
        }
        //把服务器接受到的信息发给所有的客户端
        SendMsgToAll(buf);
    }
}

void service(){
    printf("服务器启动\n");
    while(1){
        struct sockaddr_in fromaddr;
        socklen_t len = sizeof(fromaddr);
        int fd = accept(sockfd,(SA*)&fromaddr,&len);
        if (fd == -1){
            printf("客户端连接出错...\n");
            continue;
        }
        int i = 0;
        for (i = 0;i < size;i++){
            if (fds[i] == 0){
                //记录客户端的socket
                fds[i] = fd;
                printf("fd = %d\n",fd);
                //有客户端连接之后,启动线程给此客户服务
                pthread_t tid;
                pthread_create(&tid,0,service_thread,&fd);
                break;
            }
        if (size == i){
            //发送给客户端说聊天室满了
            char* str = "对不起,聊天室已经满了!";
            send(fd,str,strlen(str),0); 
            close(fd);
        }
        }
    }
}

int main(){
    init();
    service();
    return 0;
}

а потом:

gcc -o server server.c -plthread

это может сработать. Кстати, я использую vscode для добавления нового файла .c. После добавления пустых строк файл .c распознается как файл C. На его значке есть огромная буква C, часто добавляющая пустые строки. вот так

person jessic wang    schedule 20.04.2020
comment
Проблем еще много. Системный вызов возвращает не полностью обработанный способ передачи fd потоку (небезопасно передавать адрес локального объекта, который может быть перезаписан или исчезнуть до того, как поток сможет его разыменовать), вызов strlen в SendMsgToAll (но не гарантированное завершение NUL). - person Martin James; 20.04.2020
comment
Можете быть более конкретными? Поскольку я мало знаю о многопоточности, большое спасибо! - person jessic wang; 20.04.2020