从socket插入recv后的SEGFAULT

时间:2015-06-24 14:48:51

标签: c++ linux sockets pthreads

我有下一个麻烦:从套接字接收数据后,服务器应用程序会生成段错误和关闭。客户端和服务器端的代码如下。

服务器:

#include <iostream>
#include <sys/socket.h>
#include <netdb.h>
#include <vector>
#include <arpa/inet.h>
#include <string.h>
#include <algorithm>
#include <unistd.h>
#include <pthread.h>

using namespace std;

static const int PORT= 20202;
static const string HOST = "127.0.0.1";
static const int MAX_CLIENTS = 10;


struct THREADINFO {
pthread_t thread_ID;
int sockfd;
string nick;
};

struct PACKAGE{
    string nick;
    string buff;
};


int compare( THREADINFO *a,  THREADINFO *b) {
    return a->sockfd - b->sockfd;
}



int sockfd, newfd;
THREADINFO thread_info[10];
vector<THREADINFO> client_list;
pthread_mutex_t clientlist_mutex;
void *client_handler(void *fd);
int main(){
    int err_ret, sin_size;
    sockaddr_in serv_addr, client_addr;
    pthread_mutex_init(&clientlist_mutex, NULL);

    /* open a socket */
    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        err_ret = errno;
        cerr << "socket() failed..." <<endl;
        return err_ret;
    }

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT);
    serv_addr.sin_addr.s_addr = inet_addr(HOST.c_str());
    memset(&(serv_addr.sin_zero), 0, 8);

    if(bind(sockfd, (sockaddr *)&serv_addr, sizeof(sockaddr)) == -1) {
        err_ret = errno;
        cerr << "bind() failed..." <<endl;
        return err_ret;
    }

    if(listen(sockfd, MAX_CLIENTS) == -1) {
        err_ret = errno;
        cerr << "listen() failed...." <<endl;

        return err_ret;
    }

    cout << "Starting socket listener.." << endl;
    while(1) {
        sin_size = sizeof( sockaddr_in);
        if((newfd = accept(sockfd, ( sockaddr *)&client_addr, (socklen_t*)&sin_size)) == -1) {
            err_ret = errno;
            cerr << "accept() failed..." <<endl;
            return err_ret;
        }
        else {
            if(client_list.size() == MAX_CLIENTS) {
                cerr << "Connection full, request rejected..." <<endl;
                continue;
            }
            cout << "Connection requested received"<<endl;
            THREADINFO threadinfo;
            threadinfo.sockfd = newfd;
            threadinfo.nick = "Anonymous";
            pthread_mutex_lock(&clientlist_mutex);
            client_list.push_back(threadinfo);
            pthread_mutex_unlock(&clientlist_mutex);
            pthread_create(&threadinfo.thread_ID, NULL, client_handler, (void *)&threadinfo);
        }
    }
    return 0;
}

vector<THREADINFO>::iterator findThread(vector<THREADINFO>& vector1,THREADINFO& threadInfo){

    for (auto item = vector1.begin();item != vector1.end();++item){
        if (compare(&(*item),&threadInfo) == 0){
            return item;
        }
    }
}

void *client_handler(void *fd) {
     THREADINFO threadinfo = *(THREADINFO *)fd;
     PACKAGE package;
        int bytes, sent;
        while(1) {
        bytes = recv(threadinfo.sockfd, (void *)&package, sizeof(PACKAGE), 0);
        if(!bytes) {
            cerr << "Connection lost from " << threadinfo.nick;
            pthread_mutex_lock(&clientlist_mutex);
            if (!client_list.empty()) {
                client_list.erase(findThread(client_list,threadinfo));
            }
            pthread_mutex_unlock(&clientlist_mutex);
            break;
        }
            cout<< package.nick << " : " << package.buff << endl;
            pthread_mutex_lock(&clientlist_mutex);
                for (size_t i=0;i<client_list.size();i++){
                 PACKAGE spacket;
                if(!compare(&client_list[i], &threadinfo)) continue;
                    spacket.nick = package.nick;
                    spacket.buff = package.buff;
                    sent = send(client_list[i].sockfd, (void *)&spacket, sizeof( PACKAGE), 0);

                }
            pthread_mutex_unlock(&clientlist_mutex);


         if(package.buff.compare("exit") == 0) {
             cout << "Client is disconnected" << endl;

            pthread_mutex_lock(&clientlist_mutex);
             if (!client_list.empty()) {
                 client_list.erase(findThread(client_list,threadinfo));
             }
            pthread_mutex_unlock(&clientlist_mutex);
            break;
        }
        else {
             cerr << "Garbage data from " << threadinfo.sockfd <<" " <<threadinfo.nick;
        }
    }

    /* clean up */
    close(threadinfo.sockfd);

    return NULL;
}

客户端:

#include <iostream>
#include <netdb.h>
#include <pthread.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>

using namespace std;

static const int PORT = 20202;
static const string HOST = "127.0.0.1";
void *receiver(void *param);

struct PackageInfo{
    string nick;
    string buff;
};

struct User{
    int sockfd;
    string nick;
};
struct ThreadInfo{
    pthread_t thread;
    int sockfd;

};


int isDisconnected,sockfd;


int connectWithServer(){
    int newfd, err_ret;
     sockaddr_in serv_addr;
     hostent *to;

    if((to = gethostbyname(HOST.c_str()))==NULL) {
        err_ret = errno;
        cerr<<"HOST ERROR" << endl;
        return err_ret;
    }

    if((newfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        err_ret = errno;
        cerr<<"SOCKET ERROR" << endl;
        return err_ret;
    }

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT);
    serv_addr.sin_addr = *(( in_addr *)to->h_addr);
    memset(&(serv_addr.sin_zero), 0, 8);

    if(connect(newfd, ( sockaddr *)&serv_addr, sizeof( sockaddr)) == -1) {
        err_ret = errno;
        cerr << "CONNECT ERROR"<<endl;
        return err_ret;
    }
    else {
        cout << "CONNECTED!"<<endl;
        return newfd;
    }
}

void login(User* client){
    if(isDisconnected){
        cerr << "You'are disconnected";
        return;
    }
    sockfd = connectWithServer();
    if(sockfd >= 0) {
        isDisconnected = 1;
        client->sockfd = sockfd;
        cout << "Logged in as " << client->nick << endl;
        ThreadInfo threadinfo;
        pthread_create(&threadinfo.thread, NULL, receiver, (void *)&threadinfo);

    }
    else {
        cerr << "Connection rejected..." << endl;
    }


}

void *receiver(void *param){
    int recvd;
    PackageInfo package;

    cout << "Waiting server..." << endl;

    while (isDisconnected){
        recvd = recv(sockfd, (void *)&package, sizeof( PackageInfo), 0);
        if (!recvd){
            cerr << "Connection lost";
            isDisconnected = 0;
            close(sockfd);
            break;
        }
        if(recvd > 0){
            cout << package.nick << " : " << package.buff<<endl;
        }
    }
    return NULL;

}

void sentToServer( User* client,string& message){
    int sent;
    PackageInfo package;

    if(!isDisconnected) {
        cerr << "\"You are not connected..." << endl;
        return;
    }

    package.nick = client->nick;
    package.buff = message;


    sent = send(sockfd, (void *)&package, sizeof(PackageInfo), 0);

}

int main() {
    User user;
    cout << "Enter nickname: ";
    getline(cin,user.nick);
    login(&user);
        string message;
    while (cin >> message){
        sentToServer(&user,message);
    }
    return 0;
}

换句话说,客户端连接成功。但是在发送消息后,服务器会生成segm错误。什么地方出了错?

2 个答案:

答案 0 :(得分:1)

运行代码时,它会出现以下错误:

struct PACKAGE{ char nick[1024]; char buff[1024];};

Package是一个包含两个成员nick和buff的结构。然后你读取大小为16的PACKAGE结构的套接字。我想这不是你想要的。也许你可以将nick和buff指定为固定长度的char数组。

jekyll serve

答案 1 :(得分:0)

您没有使用任何数据初始化threadinfo.thread_ID。您应该定义新的pthread_t,然后将其作为参数传递给pthread_create()