如下实现多线程阻塞SOCKET AcceptSocket;
SOCKADDR_IN addrClient;
int addrClientLen = sizeof(SOCKADDR);
printf("Waiting for client to connect...\n");
while(1) {
if( (AcceptSocket = accept( ListenSocket1, (SOCKADDR *)&addrClient, &addrClientLen)) != SOCKET_ERROR ) {
ConnectInfor * conInf = new ConnectInfor();
conInf->addrClient = addrClient;
conInf->sock = AcceptSocket;
CreateThread(NULL,0,SocketThread,(LPVOID)conInf,0,NULL);  
} }线程代码DWORD WINAPI SocketThread(LPVOID lpmess)  
{   
ConnectInfor * conInf = (ConnectInfor *)lpmess;

char conType;
int bytesRecv;

bytesRecv = getByte(conInf->sock,conType);
if ( bytesRecv <= 0 || bytesRecv == WSAECONNRESET ) {
return 0;
} switch(conType)
{
case CAMERA:
cameraNet(conInf);
break;
case PLAYER:
playerNet(conInf);
break;
} closesocket(conInf->sock);
printf("close sock\n");
delete conInf;


return 0; //最后不要忘记返回一个DWORD    

现有客户端1
send一个字节,再recv255个字节,然后closesocket客户端2
循环 send一个字节,再recv255个字节。
服务器对应处理代码为void cameraNet(ConnectInfor * conInf)
{
SOCKET ListenSocket = conInf->sock;
char sendbuf[32] = "Server: Sending data.";
char recvbuf[32] = ""; int bytesSent;
int bytesRecv = SOCKET_ERROR;
printf("camera connect\n");
Camera  camera  ;
camera.getCameraInf(conInf);
connectCameraList[camera.id] = camera;
while(true)
{
char b;
bytesRecv = getByte(ListenSocket,b);
if ( bytesRecv <= 0 || bytesRecv == WSAECONNRESET ) {
break;
} switch(b)
{
 
case 100:
{
bytesSent = send( ListenSocket, sendbuf, strlen(sendbuf), 0 );
bytesRecv = recv( ListenSocket, recvbuf, 32, 0 );
if ( bytesRecv <= 0 || bytesRecv == WSAECONNRESET ) {
printf( "Bytes Recv from %d(ip = %s:%d): Connection Closed\n",ListenSocket,inet_ntoa(conInf->addrClient.sin_addr),htons(conInf->addrClient.sin_port) );
break;
}
printf("from client recive: %s\n",recvbuf);
 
}
break;
}
Sleep(0);
}
printf("camera desconnect\n");
connectCameraList.erase(camera.id);
}
现象:
只启动n个客户端1,工作正常(这是当然的)
启动n个客户端2,第一个正常,第二个以上不能连接。
启动1个客户端2,再启动一个客户端1,工作正常,但再启动一个客户端2,也连接失败。
请问问题有可能出现在哪里呢?
是不是对应循环发送消息的线程需要将socket休眠之类的?

解决方案 »

  1.   

    发觉问题不是出现在服务器端,是出现在客户端。
    因为要实现TCP穿越,connect之前必须将几个socket绑定在一个固定端口上。sockaddr_in server; 
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = inet_addr( "127.0.0.1" );
    server.sin_port = htons( 27015 ); sockaddr_in myAddress; 
    myAddress.sin_family = AF_INET;
    myAddress.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
    myAddress.sin_port = htons( C_SERVER_LISTEN_POINT );
    int flag=1,len=sizeof(int);  setsockopt(ConnectSocket,   SOL_SOCKET,   SO_REUSEADDR,   (char*)&flag,   sizeof(flag));    if (bind( ConnectSocket, 
    (SOCKADDR*) &myAddress, 
    sizeof(myAddress)) == SOCKET_ERROR) {
    printf("bind() failed.\n");
    closesocket(ConnectSocket);
    return;

    //----------------------
    // Connect to server.
    if ( connect( ConnectSocket, (SOCKADDR*) &server, sizeof(server) ) == SOCKET_ERROR) {
    printf( "Failed to connect.\n" );
    WSACleanup();
    return;
    }上面setsockopt(ConnectSocket,   SOL_SOCKET,   SO_REUSEADDR,   (char*)&flag,   sizeof(flag));    if (bind( ConnectSocket, 
    (SOCKADDR*) &myAddress, 
    sizeof(myAddress)) == SOCKET_ERROR) {
    printf("bind() failed.\n");
    closesocket(ConnectSocket);
    return;
    } 去掉了就正常了。
    但是做TCP穿越必须用端口复用技术,在一个进程中将多个socket绑定在一个端口上。但多了以上代码多线程加阻塞就出问题了。请做过TCP穿越的前辈给给经验。
      

  2.   

    问题解决了,换个端口就行。ool tcpConnect()
    {
    //----------------------
    // Initialize Winsock
    WSADATA wsaData;
    int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
    if (iResult != NO_ERROR)
    printf("Error at WSAStartup()\n"); //----------------------
    // Create a SOCKET for connecting to server
    SOCKET ConnectSocket;
    ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (ConnectSocket == INVALID_SOCKET) {
    printf("Error at socket(): %ld\n", WSAGetLastError());
    WSACleanup();
    return false;
    } //----------------------
    // The sockaddr_in structure specifies the address family,
    // IP address, and port of the server to be connected to.
    sockaddr_in server; 
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = inet_addr( "127.0.0.1" );
    server.sin_port = htons( 27015 ); sockaddr_in myAddress; 
    myAddress.sin_family = AF_INET;
    myAddress.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
    myAddress.sin_port = htons( C_SERVER_LISTEN_POINT );
    int flag=1,len=sizeof(int);  setsockopt(ConnectSocket,   SOL_SOCKET,   SO_REUSEADDR,   (char*)&flag,   sizeof(flag));    if (bind( ConnectSocket, 
    (SOCKADDR*) &myAddress, 
    sizeof(myAddress)) == SOCKET_ERROR) {
    printf("bind() failed.\n");
    closesocket(ConnectSocket);
    WSACleanup();
    return false;

    //----------------------
    // Connect to server.
    if ( connect( ConnectSocket, (SOCKADDR*) &server, sizeof(server) ) == SOCKET_ERROR) {
    printf( "Failed to connect.\n" );
    WSACleanup();
    return false;
    } //----------------------
    // Declare and initialize variables.
    int bytesSent;
    int bytesRecv = SOCKET_ERROR;
    char sendbuf[32] = "Client: Sending data.";
    char recvbuf[32] = "";
    char cameraId[255] = "test id"; sendByte(CAMERA,ConnectSocket);
    bytesSent = send( ConnectSocket, cameraId, 255, 0 );
    printf( "Bytes Sent: %ld\n", bytesSent ); sendByte(CAMERA_REGISTER,ConnectSocket);
    while(true)
    { /*sendInt(100,ConnectSocket);*/
    sendByte(100,ConnectSocket);
    bytesRecv = recv( ConnectSocket, recvbuf, 32, 0 );
    if ( bytesRecv <= 0 || bytesRecv == WSAECONNRESET ) {
    printf( "Connection Closed.\n");
    break; }
    printf( "Bytes Recv: %ld %s\n", bytesRecv,recvbuf );
    bytesSent = send( ConnectSocket, sendbuf, strlen(sendbuf), 0 );
    printf( "Bytes Sent: %ld\n", bytesSent );
    Sleep(3000);
    } closesocket(ConnectSocket); WSACleanup();
    return true;
    }
    void main() {
    while(!tcpConnect())
    {
    printf("using port %d false \n",C_SERVER_LISTEN_POINT);
    C_SERVER_LISTEN_POINT++;
    printf("try port %d false \n",C_SERVER_LISTEN_POINT);
    }
    }方法比较笨拙,呵呵