问个socket的问题。

RyanPoy 2007-06-12
在写socket程序的时候,现在出现了一个问题。具体的是什么原因,没有找到。google上和论坛里都没有找到。请大人们帮忙解决。问题是这样的:一个Server端。一个Client端。Server接收数据时候,因为client端的socket关闭了。(是我手动关闭的,用来模拟数据传输失败的场景),结果Server端的程序都死掉了。实在是找不出原因。本人采用的操作系统:Server端是红帽企业版3.0,client是windows。编程语言:Server端是c++,client是java。现在把代码贴出来。如下。
RyanPoy 2007-06-12
socket的封装的头文件:
#ifndef __BASE_SOCKET__
#define __BASE_SOCKET__

#define _LINUX__

#ifdef _WIN32__
    #pragma comment(lib, "ws2_32.lib")
#endif 
    
#ifdef _LINUX__
    #include <unistd.h>
    #include <netinet/in.h>
    #include <sys/socket.h>
    #include <sys/types.h>
    #include <arpa/inet.h>
    #ifndef SOCKET
        #define SOCKET int
    #endif
#endif
    
#define _TCP 0
#define _UDP 1

#define SOCKET_EXCEPTION -1

class BaseSocket
{
protected:
    struct sockaddr_in addr;    
    SOCKET sock;

public:
    BaseSocket();
    BaseSocket(SOCKET sock);
    BaseSocket(const BaseSocket& bsocket);
    ~BaseSocket();

    bool operator == (const BaseSocket& s)
    {
        return sock == s.sock;
    };

    unsigned short getPort() const;
    char* getIP() const;

    static bool init();
    static bool destroy();

    bool create(int type = _TCP);
    bool isValid();
    bool close();

    bool bind(unsigned short port);
    bool listen(int num = 5);
    BaseSocket accept();
    bool connect(const char* ip, unsigned short port);

    bool recvChar(char* v);
    bool recvShort(short* v);
    bool recvInt(int* v);
    bool recvLong(long* v);
    bool recvI64(I64* v);
    bool recvStr(char* str, int len);

    bool send(char data);
    bool send(short data);
    bool send(int data);
    bool send(long data);
    bool send(I64 data);
    bool send(U_I64 data);
    bool send(char* str, int len);
    bool setTimeOut(int millSec);

protected:
    bool createTCP();
    bool createUDP();
    bool realCreate(int af = AF_INET, int type = SOCK_STREAM, int protocol = IPPROTO_TCP);
};

#endif //~__BASE_SOCKET__

RyanPoy 2007-06-12
socket封装的实现文件
#include "BaseSocket.h"
#include <cstdio>

BaseSocket::BaseSocket(): sock(-1){}

BaseSocket::BaseSocket(SOCKET sock): sock(sock){}

BaseSocket::BaseSocket(const BaseSocket& bsocket): sock(bsocket.sock), addr(bsocket.addr){}

BaseSocket::~BaseSocket(){}

bool BaseSocket::recvChar(char* v)
{
    return recvStr(v, sizeof(char));
}

//-------------------------------------------------------------------------

bool BaseSocket::recvShort(short* v)
{
    return recvStr((char*) v, sizeof(short));
}

//-------------------------------------------------------------------------

bool BaseSocket::recvInt(int* v)
{
    return recvStr((char*) v, sizeof(int));
}

//-------------------------------------------------------------------------

bool BaseSocket::recvLong(long* v)
{
    return recvStr((char*) v, sizeof(long));
}

//-------------------------------------------------------------------------

bool BaseSocket::recvI64(I64* v)
{
    return recvStr((char*) v, sizeof(v));
}

//-------------------------------------------------------------------------
bool BaseSocket::recvStr(char* str, int len)
{
    if (NULL == str || 0 > len)
        return false;

    if (len == 0)
        return true;

    int recvLen = ::recv(sock, str, len, 0);
    if (recvLen <= 0)
    {
#ifdef _WIN32__
            printf("socket recv error? %d\n", GetLastError());
#endif
#ifdef _LINUX__
            printf("socket recv error? %d : %s \n", errno, strerror(errno));
#endif
        return false;
    }
    
    while (recvLen < len)
    {
        int relt = ::recv(sock, str + recvLen, len - recvLen, 0);

        if (relt <= 0)
        {
#ifdef _WIN32__
            printf("socket recv error? %d\n", GetLastError());
#endif
#ifdef _LINUX__
            printf("socket recv error? %d : %s \n", errno, strerror(errno));
#endif
            return false;
        }

        recvLen += relt;
    }

    return true;
}

//-------------------------------------------------------------------------

bool BaseSocket::send(char data)
{
    return send(&data, sizeof(data));
}

//-------------------------------------------------------------------------

bool BaseSocket::send(short data)
{
    return send((char*)& data, sizeof(data));
}

//-------------------------------------------------------------------------

bool BaseSocket::send(int data)
{
    return send((char*)& data, sizeof(data));
}

//-------------------------------------------------------------------------

bool BaseSocket::send(long data)
{
    return send((char*)& data, sizeof(data));
}

//-------------------------------------------------------------------------

bool BaseSocket::send(I64 data)
{
    return send((char*)& data, sizeof(data));
}

//-------------------------------------------------------------------------

bool BaseSocket::send(U_I64 data)
{
    return send((char*)& data, sizeof(data));
}

//-------------------------------------------------------------------------

bool BaseSocket::send(char* str, int len)
{
	int sendLen = ::send(sock, str, len, 0);
	if (sendLen < 0)
	{
#ifdef _WIN32__
		printf("socket send error: %d\n", GetLastError());
#endif
#ifdef _LINUX__
		printf("socket send error: %d, %s\n", errno, strerror(errno));
#endif
		return false;
	}
	while(sendLen < len)
	{
		int relt = ::send(sock, str + sendLen, len - sendLen, 0);
		if (relt < 0)
		{
#ifdef _WIN32__
			printf("socket send error: %d\n", GetLastError());
#endif
#ifdef _LINUX__
			printf("socket send error: %d, %s\n", errno, strerror(errno));
#endif
			return false;
		}
		sendLen += relt;
	}

    return true;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool BaseSocket::create(int type)
{
    switch (type)
    {
        case _TCP:	// (0)_TCP: connection
            return createTCP();
        case _UDP:  // (1)_UDP: connection
            return createUDP();
        default:
            return false;
    }
}

//-------------------------------------------------------------------------

bool BaseSocket::createTCP()
{
    return realCreate(AF_INET, SOCK_STREAM, IPPROTO_TCP);
}

//-------------------------------------------------------------------------

bool BaseSocket::createUDP()
{
    return realCreate(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
}

//-------------------------------------------------------------------------

bool BaseSocket::realCreate(int af, int type, int protocol)
{
    sock = socket(af, type, protocol);
    if (!isValid())
	{
#ifdef _WIN32__
		printf("Create Connect(protocol NO.%d) Error ! : %d\n", protocol, GetLastError());
#endif
#ifdef _LINUX__
		printf("Create Connect(protocol NO.%d) Error ! : %d, %s\n", protocol, errno, strerror(errno));
#endif
		return false;
	}
	return true;
}

//-------------------------------------------------------------------------

BaseSocket BaseSocket::accept()
{
    struct sockaddr_in clientAddr;
    //	memset(&clientAddr, 0x00, sizeof(clientAddr));
#ifdef _WIN32__
    int len = sizeof(sockaddr_in);
#endif
#ifdef _LINUX__
    socklen_t len = sizeof(sockaddr_in);
#endif
    SOCKET sClient = ::accept(sock, (struct sockaddr*)& clientAddr, &len);
    BaseSocket s(sClient);
    s.addr = clientAddr;
    if (!isValid())
    {
#ifdef _WIN32__
            printf("Accept Error ! : %d\n", GetLastError());
#endif
#ifdef _LINUX__
            printf("Accept Error ! : %d, %s\n", errno, strerror(errno));
#endif
    }
    else
    {
            printf("accept client connection : %s -- %d\n", inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port));
    }
    return s;
}

//-------------------------------------------------------------------------

bool BaseSocket::connect(const char* ip, unsigned short port)
{
    struct sockaddr_in serverAddr;
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(port);
    serverAddr.sin_addr.s_addr = inet_addr(ip);
	
	if (-1 == ::connect(sock, (struct sockaddr*)& serverAddr, sizeof(struct sockaddr)))
	{
#ifdef _WIN32__
		printf("Socket Connect Error: %d\n", GetLastError());
#endif
#ifdef _LINUX__
		printf("Socket Connect Error: %d, %S\n", errno, strerror(errno));
#endif
		return false;
	}
    printf("socket %s:%d connect.\n", getIP(), getPort());
    return true;
}

//-------------------------------------------------------------------------

bool BaseSocket::close()
{
    printf("socket %s:%d close.\n", getIP(), getPort());
#ifdef _WIN32__
    if (-1 == ::closesocket(sock))
    {
        printf("socket close error!\n", GetLastError());
        return false;
    }
#endif
#ifdef _LINUX__
    if (-1 == ::close(sock))
    {
        printf("socket close error! %d, %s\n", errno, strerror(errno));
        return false;
    }
#endif
    return true;
}

//-------------------------------------------------------------------------

bool BaseSocket::bind(unsigned short port)
{
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    memset(&addr.sin_zero, 0x00, sizeof(addr.sin_zero));
	
	if (-1 == ::bind(sock, (struct sockaddr*)& addr, sizeof(struct sockaddr)))
	{
#ifdef _WIN32__
		printf("socket bind error! %d\n", GetLastError());
#endif
#ifdef _LINUX__
		printf("socket bind error! %d: %s\n", errno, strerror(errno));
#endif
		return false;
	}
	return true;
}

//-------------------------------------------------------------------------

bool BaseSocket::listen(int num)
{
	if (-1 == ::listen(sock, num))
	{
#ifdef _WIN32__ 
		printf("listen error! %d\n", GetLastError());
#endif
#ifdef _LINUX__
		printf("listen error! %d: %s", errno, strerror(errno));
#endif

		return false;
	}
	return true;
}

//-------------------------------------------------------------------------

bool BaseSocket::isValid()
{
    return -1 != sock;
}

//-------------------------------------------------------------------------

unsigned short BaseSocket::getPort() const
{
    return (unsigned short) (::ntohs(addr.sin_port));
}

//-------------------------------------------------------------------------

char* BaseSocket::getIP()const
{
	char* p = ::inet_ntoa(addr.sin_addr);
	if (NULL == p)
	{
#ifdef _WIN32__
		printf("Socket Get IP Error: %d\n", GetLastError());
#endif
#ifdef _LINUX__
		printf("Socket Get IP Error: %d, %s\n", errno, strerror(errno));
#endif
	}
    return p;
}

//-------------------------------------------------------------------------

bool BaseSocket::setTimeOut(int milliSec)
{
    if (!isValid())
        return false;
    
#ifdef _WIN32__	
    int time = milliSec;
#endif
#ifdef _LINUX__
    
    struct timeval time;
    time.tv_sec = (milliSec / 1000);//???
#endif
	if (-1 == setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char*)& time, sizeof(time)))
	{
#ifdef _WIN32__
		printf("Socket Set Timeout Error: %d\n", GetLastError());
#endif

#ifdef _LINUX__
		printf("Socket Set Timeout Error: %d, %s\n", errno, strerror(errno));
#endif
		return false;
	}
    
        if (-1 == setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char*)& time, sizeof(time)))
	{
#ifdef _WIN32__
		printf("Socket Set Timeout Error: %d\n", GetLastError());
#endif

#ifdef _LINUX__
		printf("Socket Set Timeout Error: %d, %s\n", errno, strerror(errno));
#endif
		return false;
	}
	return true;
}

//-------------------------------------------------------------------------

bool BaseSocket::init()
{
#ifdef _WIN32__
	WSAData wsaData;
	if (0 != WSAStartup(MAKEWORD(2, 2), &wsaData))
	{
		printf("WSA Startup Error : %d \n", GetLastError());
		return false;
	}
	return true;
#else
	return true;
#endif  
}

//-------------------------------------------------------------------------

bool BaseSocket::destroy()
{
#ifdef _WIN32__
	if (0 != WSACleanup())
	{
		printf("WSA Startup Error : %d \n", GetLastError());
		return false;
	}
	return true;
#else
	return true;
#endif  
    
}

RyanPoy 2007-06-12
main方法
int main(int argc, char* argv[])
{
    BaseSocket qsSocket;
    
    if (!qsSocket.create(_TCP))
        return -1;
    if (!qsSocket.bind((unsigned short) 8888))
        return -1;
    if (!qsSocket.listen(5))
        return -1;
    
    char* str= "Logger.default.grade=INFO;中国人名共和国";
    int len = (int) strlen(str);
    BaseSocket csock = qsSocket.accept();
    int v;
    while(true)
    {
        csock.send(len);
        csock.send(str, len);
        csock.recvInt(&v);
        printf("v = %d\n", v);
    }
    return 0;
}
RyanPoy 2007-06-12
上面是server的测试代码。client的是java写的。就不帖了。但是,当client端关闭的时候,整个应用程序都死掉了。我看了一下server的错误信息,是:socket recv error 104 : Connection reset by peer.但是,一个socket通信失败,不应该把整个程序都down掉啊。实在找不出原因了。请赐教
RyanPoy 2007-06-13
大侠们都来看看啊。阿!
qiezi 2007-06-14
客户端和服务器是在内网吗?通常断开服务器会得到通知,这时recv返回是0。但非正常断开则不一定,比如拔网线,这可能要等到TCP超时,这个时间非常长。这样阻塞接收最好是设一下socket超时,通常编写服务器最好是采用事件方式,有数据时处理,而不是这样阻塞线程,当然简单应用是可以的。
RyanPoy 2007-06-14
这个东西,找到原因.是因为,socket接受或者发送数据失败的时候, 系统给了一个sigpipe信号.导致程序退出.现在这个问题倒是解决了.注册一个信号捕捉函数.然后处理就可以了.

qiezi 写道
客户端和服务器是在内网吗?通常断开服务器会得到通知,这时recv返回是0。但非正常断开则不一定,比如拔网线,这可能要等到TCP超时,这个时间非常长。

是内网.而且,这个不知道为什么常常发生.表现在数据还没有完全接受完毕.然后,就出现recv的返回值为0的情况.实在不知道怎么回事了.没有办法.只能认为这次操作失败了.

qiezi 写道
这样阻塞接收最好是设一下socket超时,

我在编写程序的时候,已经设置了超时.

qiezi 写道
通常编写服务器最好是采用事件方式,有数据时处理,而不是这样阻塞线程,当然简单应用是可以的。

这个不知道怎么用.能不能举个简单的例子.能有代码最好,而且希望能配上注释. ^-^

qiezi 2007-06-14
那是broken pipe,是要处理掉的。

事件方式最简单的可以采用select,跨平台,搜索一下就有了。更深入点的,windows上有IOCP,linux下有poll/epoll/aio等。
RyanPoy 2007-06-14
qiezi 写道
那是broken pipe,是要处理掉的。

事件方式最简单的可以采用select,跨平台,搜索一下就有了。更深入点的,windows上有IOCP,linux下有poll/epoll/aio等。


多谢。不懂再请教。
Global site tag (gtag.js) - Google Analytics