SOCKET立即响应

atao245993 2007-03-05 04:02:04
使用SOCKET,
client连接server,server新开一个接收线程,并记录下client的SOCKET参数。
因为server将有大量连接,所以未采用select机制。server对每个接收线程采用阻塞循环隔一秒读取一次SOCKET,收到信息后立即返回响应包给client。
client采用select检测是否有信息可读。

当client主动发送信息给server,server收到并立即返回给响应包,client收到状态响应包。
上面这些部分都OK了。

现在的问题是:
当server主动发信息给client后,client的select检测不到新信息;直到client再次发信息给server时,才能将先前server主动发出的信息读出。

感觉好象server主动发送时,SOCKET一直在阻塞状态,直到client发生send操作才激活。

如何让server发出信息后,client马上有反应?
...全文
378 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
atao245993 2007-03-29
  • 打赏
  • 举报
回复
几天没上线,今天来结贴了.
「已注销」 2007-03-12
  • 打赏
  • 举报
回复
mark
pp616 2007-03-09
  • 打赏
  • 举报
回复
分享是种美德。
atao245993 2007-03-09
  • 打赏
  • 举报
回复
server和client都用select机制,阻塞问题解决.server发送后,client马上收到.


继续探讨保存SOCKET信息方法

看到一个示例,与大家共享
//主函数

void main()

{

//加载socket2.2支持

DWORD wVerRqst;

wVerRqst=MAKEWORD(2,2);

WSAData wsaData;

if(::WSAStartup(wVerRqst,&wsaData) != 0)

{

cout<<"加载socket2.2支持失败."<<endl;

getch();

exit(0);

}

//建立socket

SOCKET skt;

skt=::socket(PF_INET,SOCK_STREAM,0);

if(skt == INVALID_SOCKET)

{

cout<<"创建socket失败."<<endl;

exitSocket();

}

//绑定到本地地址

sockaddr_in sas;//sockaddr server

sas.sin_family=AF_INET;

sas.sin_addr.s_addr=INADDR_ANY;

sas.sin_port=::htons(21);

memset(&sas.sin_zero,0,sizeof(sas.sin_zero));

if(::bind(skt,(sockaddr*)&sas,sizeof(sas)) != 0)

{

cout<<"绑定到本地地址出错."<<endl;

exitSocket();

}

//在本地地址(端口)侦听连接

if(::listen(skt,20) != 0)

{

cout<<"在指定端口侦听出错."<<endl;

exitSocket();

}

//启动消息分发线程

DWORD trdMsgPoster;

::CreateThread(NULL,NULL,

(LPTHREAD_START_ROUTINE)sendMsg,

0,0,&trdMsgPoster);

//开始接受连接

cout<<"等待客户端连接..."<<endl;

while(true)

{

SOCKET clientSkt;

clientSkt=::accept(skt,NULL,NULL);

if(clientSkt == INVALID_SOCKET)

{

cout<<"接受socket出错."<<endl;

exitSocket();

}

cout<<"接受到一个连接."<<endl;

//启动子线程和客户端对话

DWORD trd;

::CreateThread(NULL,NULL,

(LPTHREAD_START_ROUTINE)clientHandler,

(LPVOID)clientSkt,0,&trd);

}

//退出,清理

::WSACleanup();

exit(0);

}

//线程回调函数
void clientHandler(LPVOID pClientSkt)

{

SOCKET skt=(SOCKET)pClientSkt;

//对话:用户名

//接受客户端输入

char clientUserName[100]={0};

::recv(skt,clientUserName,sizeof(clientUserName),0);

//给客户端发送消息

char info[500]={0};

strcpy(info,"欢迎您,");

strcat(info,clientUserName);

strcat(info,"!这里是winlin大学程序实验室.");

::send(skt,info,strlen(info),0);

//添加到用户列表

clientList.push_back(skt);

//通知聊天室有新用户来了

string login="用户";

login.append(clientUserName);

login.append("进入了聊天室.");

msgQueue.push(login);

//接受用户消息

while(true)

{

::Sleep(100);

char msg[500]={0};

if(::recv(skt,msg,sizeof(msg),0) == SOCKET_ERROR)

{

//用户退出

string quit="用户";

quit.append(clientUserName);

quit.append("退出了聊天室.");

msgQueue.push(quit);

//关闭并退出

clientList.remove(skt);

::closesocket(skt);

break;

}

else

{

string smsg="";

smsg.append("来自");

smsg.append(clientUserName);

smsg.append("的消息:\n");

smsg.append(msg);

msgQueue.push(smsg);

}

}

}
//给所有客户端发送消息

void sendMsg()

{

while(true)

{

::Sleep(100);

if(msgQueue.empty())

{

continue;

}

string msg=msgQueue.front();

msgQueue.pop();

for(list<SOCKET>::iterator iter=clientList.begin();

iter!=clientList.end();)

{

SOCKET skt=*(iter++);

::send(skt,msg.c_str(),msg.length(),0);

}

}

}
atao245993 2007-03-08
  • 打赏
  • 举报
回复
我在server的接收线程里用了recv阻塞,在线程外直接进行send操作时,也被阻塞了,所以出现最上面的那个问题.

现在在探讨accept后新建连接接收线程,如何准确传递SOCKET信息.最好有样例代码.
atao245993 2007-03-08
  • 打赏
  • 举报
回复
现在又发现一个问题,SOCKET信息记录不准确.SERVER回复信息时有时会串位,有时候客户A会收到本该客户B的信息.
请教准确保存SOCKET信息的方法.

以下是我的简化的部分代码:

//自定义结构,存放SOCKET信息
typedef struct _THREAD_PARAM
{
SOCKET *soc;
int *tid;
}THREAD_PARAM;

SOCKET _serversoc;
struct sockaddr_in client;
HANDLE _hlisten[nXYHF_LISTEN_NUM]; //监听线程
------------------------
//lisen部分
int _beginlisten(unsigned short port)
{
int ServeSocket = -1;
struct sockaddr_in ServeAddr;
int flag = 1;
int len = 4;
ServeSocket = socket(AF_INET,SOCK_STREAM,0);
if ( ServeSocket == -1 )
return CREATE_SOCKET_FAILED;

ServeAddr.sin_family=AF_INET;
ServeAddr.sin_port=htons(port);
//ServeAddr.sin_addr=INADDR_ANY;
ServeAddr.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
setsockopt(ServeSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&flag, len);
if ( bind(ServeSocket,(struct sockaddr*)&ServeAddr, sizeof(ServeAddr)) < 0 )
return BIND_SOCKET_FAILED;

if ( listen(ServeSocket, nXYHF_LISTEN_NUM) != 0 )
return LISTEN_SOCKET_FAILED;

_serversoc = ServeSocket;

return 0;
}
------------------------
//accept客户端连接后,新建线程
.......
_beginlisten(7777);
while(1)//简化成1
{
socket = accept(_serversoc, (struct sockaddr*)&client, (int *)&size);
if ( socket > 0 )
{
for ( int i=0; i < nXYHF_LISTEN_NUM; i++)
{
if ( 0 == _hlisten[i])
{
THREAD_PARAM _tpa;
_tpa.soc = &socket;
_tpa.tid = &i;
_hlisten[i]=CreateThread(NULL,0,
(LPTHREAD_START_ROUTINE)&_receivemsg,(LPVOID)&_tpa,0,NULL);
break;
}
}
}
}
---------------------
//线程部分
void WINAPI _receivemsg(void *param)
{
THREAD_PARAM &_tpa = *(THREAD_PARAM *)param;

SOCKET &socket = *(SOCKET *)_tpa.soc; //取得接收SOCKET
int tid = *(int *)_tpa.tid;

while(1)//简化成1
{
Sleep(1000);
......
_recv(socket, (char *)&pkg, sizeof(pkg));//定时去接收信息
......
_send(socket, (char *)&pkg, sizeof(pkg));//必要时回复信息
//recv和send都使用线程安全保护
}
closesocket( socket);//关闭连接
_hlisten[tid] = 0;
}
------------------
pp616 2007-03-06
  • 打赏
  • 举报
回复
server发信息是怎么发的?
相关代码贴点上来。
我不懂电脑 2007-03-06
  • 打赏
  • 举报
回复
用TClientSocket没有这种现象。

1,316

社区成员

发帖
与我相关
我的任务
社区描述
C++ Builder 网络及通讯开发
社区管理员
  • 网络及通讯开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧