问个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等。 多谢。不懂再请教。 |

