网络数据转发问题 谢谢!!!

时间:2021-03-22 13:40:32
当客户端访问 服务器时候,服务器为每个用户分别开一个线程 并且创建Socket用于传递数据。当某个用户把数据传输给服务器时,服务器又要把接收到的数据转发给另一个用户,从接收的数据中可以知道要转发的用户的IP地址,请问转发应该怎么实现?谢谢!!

8 个解决方案

#1


建立连接后标志用户的IP地址对以后进行判断,线程之间的通讯,消息通知事件!

#2


所有的用户都跟服务器连接,服务器通过IP地址知道要转发的用户,也就是那一个线程,然后转发数据,希望各位大虾能给点代码参考,非常感谢!!!

#3


其实不需要每个用户都一个线程,实际上只需要2个线程就可以实现多用户连接.定义一个Socket数组存放所有用户连接。服务器接受消息时可以知道客户的Socket序号,然后根据Socket调用Socket的API函数得到IP地址就可以,有了IP地址就可以再调用API函数找到对于的Socket,再发送消息就可以了。

#4


谢谢上面的仁兄! 您说的:"有了IP地址就可以再调用API函数找到对于的Socket",这个功能实现的代码该怎么写?万分感谢!!!

如果按照我的做法即:“当客户端访问 服务器时候,服务器为每个用户分别开一个线程”,知道IP,怎么可以知道它对应的与服务器建立连接的线程,实现代码应该怎么写,谢谢!!!!

#5


自己顶一下!!

#6


建一个数组或链表来保存每个连接的信息结构
typedef struct _ConnInfo
{
  HANDLE hThread;
  SOCKET Socket;
  ULONG  IP;
}*P_ConnInfo;
这样知道IP后在可以在数组或链中查询对应的套接字或线程句柄,然后使用该套接发送数据.

如果一定要转到相应的线程发送数据,可以在为每个连接建立的线程中设置一个消息循环,
在查找到上述连接信息后向该线程发送消息.

Buf已知;
IP已知;
P_ConnInfo pConnInfo=List.Find(IP);//这个可以使用STL的list类或MFC的CList类,或数组
if(pConnInfo)
PostThreadMessage(pConnInfo->hThread,自定议消息,0,(LONG)Buf);

线程消息循环的建立:
void ThreadProc(void* pVoid)
{
  MSG msg;
  while(GetMessage(&msg,0,0,0))
  {
    switch(msg.lParam)//或if,看你的情况了.
    {
      消息判断及相应的处理;
    }
  } 
}

#7


#include <winsock2.h>
#include <stdio.h>

#define PORT    5150
#define MSGSIZE 1024

#pragma comment(lib, "ws2_32.lib")

int      g_iTotalConn = 0;
SOCKET   g_CliSocketArr[MAXIMUM_WAIT_OBJECTS];
WSAEVENT g_CliEventArr[MAXIMUM_WAIT_OBJECTS];

DWORD WINAPI WorkerThread(LPVOID);
void Cleanup(int index);

int main()
{
  WSADATA     wsaData;
  SOCKET      sListen, sClient;
  SOCKADDR_IN local, client;
  DWORD       dwThreadId;
  int         iaddrSize = sizeof(SOCKADDR_IN);

  // Initialize Windows Socket library
  WSAStartup(0x0202, &wsaData);

  // Create listening socket
  sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

  // Bind
  local.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
 local.sin_family = AF_INET;
 local.sin_port = htons(PORT);
  bind(sListen, (struct sockaddr *)&local, sizeof(SOCKADDR_IN));

  // Listen
  listen(sListen, 3);

  // Create worker thread
  CreateThread(NULL, 0, WorkerThread, NULL, 0, &dwThreadId);

  while (TRUE)
  {
    // Accept a connection
    sClient = accept(sListen, (struct sockaddr *)&client, &iaddrSize);
    printf("Accepted client:%s:%d\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port));

    // Associate socket with network event
    g_CliSocketArr[g_iTotalConn] = sClient;
    g_CliEventArr[g_iTotalConn] = WSACreateEvent();
    WSAEventSelect(g_CliSocketArr[g_iTotalConn],
                   g_CliEventArr[g_iTotalConn],
                   FD_READ | FD_CLOSE);
    g_iTotalConn++;
  }
}

DWORD WINAPI WorkerThread(LPVOID lpParam)
{
  int              ret, index;
  WSANETWORKEVENTS NetworkEvents;
  char             szMessage[MSGSIZE];

  while (TRUE)
  {
    ret = WSAWaitForMultipleEvents(g_iTotalConn, g_CliEventArr, FALSE, 1000, FALSE);
    if (ret == WSA_WAIT_FAILED || ret == WSA_WAIT_TIMEOUT)
    {
      continue;
    }

    index = ret - WSA_WAIT_EVENT_0;
    WSAEnumNetworkEvents(g_CliSocketArr[index], g_CliEventArr[index], &NetworkEvents);

    if (NetworkEvents.lNetworkEvents & FD_READ)
    {
      // Receive message from client
      ret = recv(g_CliSocketArr[index], szMessage, MSGSIZE, 0);
      if (ret == 0 || (ret == SOCKET_ERROR && WSAGetLastError() == WSAECONNRESET))
      {
        Cleanup(index);
      }
      else
      {
        szMessage[ret] = '\0';
        send(g_CliSocketArr[index], szMessage, strlen(szMessage), 0);
      }
    }

    if (NetworkEvents.lNetworkEvents & FD_CLOSE)
  {
   Cleanup(index);
  }
  }
  return 0;
}

void Cleanup(int index)
{
  closesocket(g_CliSocketArr[index]);
 WSACloseEvent(g_CliEventArr[index]);

 if (index < g_iTotalConn - 1)
 {
  g_CliSocketArr[index] = g_CliSocketArr[g_iTotalConn - 1];
  g_CliEventArr[index] = g_CliEventArr[g_iTotalConn - 1];
 }
 
 g_iTotalConn--;
}
以上代码节选自书籍上的代码。你的问题只要略为修改就可以达到目的。至于由sock得到ip地址可以用int getpeername(SOCKET s, struct sockaddr FAR * name, int FAR * namelen )函数。遍历sock数组调用此函数,若得到的ip于你的转发ip相等,必定是此sock了,然后send就是.

#8


UP

#1


建立连接后标志用户的IP地址对以后进行判断,线程之间的通讯,消息通知事件!

#2


所有的用户都跟服务器连接,服务器通过IP地址知道要转发的用户,也就是那一个线程,然后转发数据,希望各位大虾能给点代码参考,非常感谢!!!

#3


其实不需要每个用户都一个线程,实际上只需要2个线程就可以实现多用户连接.定义一个Socket数组存放所有用户连接。服务器接受消息时可以知道客户的Socket序号,然后根据Socket调用Socket的API函数得到IP地址就可以,有了IP地址就可以再调用API函数找到对于的Socket,再发送消息就可以了。

#4


谢谢上面的仁兄! 您说的:"有了IP地址就可以再调用API函数找到对于的Socket",这个功能实现的代码该怎么写?万分感谢!!!

如果按照我的做法即:“当客户端访问 服务器时候,服务器为每个用户分别开一个线程”,知道IP,怎么可以知道它对应的与服务器建立连接的线程,实现代码应该怎么写,谢谢!!!!

#5


自己顶一下!!

#6


建一个数组或链表来保存每个连接的信息结构
typedef struct _ConnInfo
{
  HANDLE hThread;
  SOCKET Socket;
  ULONG  IP;
}*P_ConnInfo;
这样知道IP后在可以在数组或链中查询对应的套接字或线程句柄,然后使用该套接发送数据.

如果一定要转到相应的线程发送数据,可以在为每个连接建立的线程中设置一个消息循环,
在查找到上述连接信息后向该线程发送消息.

Buf已知;
IP已知;
P_ConnInfo pConnInfo=List.Find(IP);//这个可以使用STL的list类或MFC的CList类,或数组
if(pConnInfo)
PostThreadMessage(pConnInfo->hThread,自定议消息,0,(LONG)Buf);

线程消息循环的建立:
void ThreadProc(void* pVoid)
{
  MSG msg;
  while(GetMessage(&msg,0,0,0))
  {
    switch(msg.lParam)//或if,看你的情况了.
    {
      消息判断及相应的处理;
    }
  } 
}

#7


#include <winsock2.h>
#include <stdio.h>

#define PORT    5150
#define MSGSIZE 1024

#pragma comment(lib, "ws2_32.lib")

int      g_iTotalConn = 0;
SOCKET   g_CliSocketArr[MAXIMUM_WAIT_OBJECTS];
WSAEVENT g_CliEventArr[MAXIMUM_WAIT_OBJECTS];

DWORD WINAPI WorkerThread(LPVOID);
void Cleanup(int index);

int main()
{
  WSADATA     wsaData;
  SOCKET      sListen, sClient;
  SOCKADDR_IN local, client;
  DWORD       dwThreadId;
  int         iaddrSize = sizeof(SOCKADDR_IN);

  // Initialize Windows Socket library
  WSAStartup(0x0202, &wsaData);

  // Create listening socket
  sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

  // Bind
  local.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
 local.sin_family = AF_INET;
 local.sin_port = htons(PORT);
  bind(sListen, (struct sockaddr *)&local, sizeof(SOCKADDR_IN));

  // Listen
  listen(sListen, 3);

  // Create worker thread
  CreateThread(NULL, 0, WorkerThread, NULL, 0, &dwThreadId);

  while (TRUE)
  {
    // Accept a connection
    sClient = accept(sListen, (struct sockaddr *)&client, &iaddrSize);
    printf("Accepted client:%s:%d\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port));

    // Associate socket with network event
    g_CliSocketArr[g_iTotalConn] = sClient;
    g_CliEventArr[g_iTotalConn] = WSACreateEvent();
    WSAEventSelect(g_CliSocketArr[g_iTotalConn],
                   g_CliEventArr[g_iTotalConn],
                   FD_READ | FD_CLOSE);
    g_iTotalConn++;
  }
}

DWORD WINAPI WorkerThread(LPVOID lpParam)
{
  int              ret, index;
  WSANETWORKEVENTS NetworkEvents;
  char             szMessage[MSGSIZE];

  while (TRUE)
  {
    ret = WSAWaitForMultipleEvents(g_iTotalConn, g_CliEventArr, FALSE, 1000, FALSE);
    if (ret == WSA_WAIT_FAILED || ret == WSA_WAIT_TIMEOUT)
    {
      continue;
    }

    index = ret - WSA_WAIT_EVENT_0;
    WSAEnumNetworkEvents(g_CliSocketArr[index], g_CliEventArr[index], &NetworkEvents);

    if (NetworkEvents.lNetworkEvents & FD_READ)
    {
      // Receive message from client
      ret = recv(g_CliSocketArr[index], szMessage, MSGSIZE, 0);
      if (ret == 0 || (ret == SOCKET_ERROR && WSAGetLastError() == WSAECONNRESET))
      {
        Cleanup(index);
      }
      else
      {
        szMessage[ret] = '\0';
        send(g_CliSocketArr[index], szMessage, strlen(szMessage), 0);
      }
    }

    if (NetworkEvents.lNetworkEvents & FD_CLOSE)
  {
   Cleanup(index);
  }
  }
  return 0;
}

void Cleanup(int index)
{
  closesocket(g_CliSocketArr[index]);
 WSACloseEvent(g_CliEventArr[index]);

 if (index < g_iTotalConn - 1)
 {
  g_CliSocketArr[index] = g_CliSocketArr[g_iTotalConn - 1];
  g_CliEventArr[index] = g_CliEventArr[g_iTotalConn - 1];
 }
 
 g_iTotalConn--;
}
以上代码节选自书籍上的代码。你的问题只要略为修改就可以达到目的。至于由sock得到ip地址可以用int getpeername(SOCKET s, struct sockaddr FAR * name, int FAR * namelen )函数。遍历sock数组调用此函数,若得到的ip于你的转发ip相等,必定是此sock了,然后send就是.

#8


UP