socket高手请进来指点一下

byybyybyy 2004-03-28 10:40:24
写了一个用socket收发数据(send,recv)的console程序,客户端发送,服务器端收数据并回显,最大线程数是十个(每个客户端一个),现把服务器端代码贴出来,望高手指点一下:
#include "stdafx.h"

#define NUMBER 10

SOCKET NewSocket[NUMBER];

//线程处理段,解决多连接的数据处理问题
void ProceData(PVOID ii)
{
char DataBuffer[1024];
memset(DataBuffer,0,sizeof(DataBuffer));
int i = *((int *)ii);
int Ret;
while(1)
{
if ((Ret = recv(NewSocket[i],DataBuffer,sizeof(DataBuffer),0))!= SOCKET_ERROR)
{
if (Ret > 0)
{
//printf("We Have received %d bytes from the client\n",Ret);
printf("收到的数据是: %s\n",DataBuffer);
}
}
Sleep(1);
}
}
int _tmain(int argc, _TCHAR* argv[])
{
WSADATA wsaData;
SOCKET LisenSocket;
SOCKADDR_IN Serveraddr,Clientaddr;
int Ret,ClientaddrLen;
char DataBuffer[1024];
int port = 5500;
BOOL sc = TRUE;
HANDLE hThd[NUMBER];
int nThd;

//初始化winsock 版本库
if ((Ret = WSAStartup(MAKEWORD(2,2),&wsaData)) != 0)
{
printf("WSAStartup failed with error code %d \n", Ret);
return -1;
}

//创建socket套结字

if ((LisenSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) == INVALID_SOCKET)
{
printf("Create the socket failed with error code %d\n",WSAGetLastError());
WSACleanup();
return -1;
}
Serveraddr.sin_family = AF_INET;
Serveraddr.sin_port = htons(port); //将端口地址转换为网络字节
Serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); //将ip地址转换为网络字节

if ((Ret = bind(LisenSocket,(SOCKADDR *)&Serveraddr,sizeof(Serveraddr))) == SOCKET_ERROR)
{
printf("bind the socket failed with error code %d\n",WSAGetLastError());
closesocket(LisenSocket);
WSACleanup();
return -1;
}

//监听客户机连接,确定最大连接数

listen(LisenSocket,NUMBER);

//接受一个新的连接

printf("We are waiting a connection on port %d.\n", port);

int i = 0;
int j;
ClientaddrLen = sizeof(Clientaddr);
while(i < NUMBER)
{
if ((NewSocket[i] = accept(LisenSocket, (SOCKADDR *)&Clientaddr,&ClientaddrLen)) == INVALID_SOCKET)
{
Ret = WSAGetLastError();
printf("We have tryed to accept a socket for the %d times...\n", ++i);
switch(Ret)
{
case WSANOTINITIALISED:
printf("A successful WSAStartup call must occur before using this function.\n");
break;
case WSAENETDOWN:
printf("The network subsystem has failed.\n");
break;
case WSAEFAULT:
printf("The addrlen parameter is too small or addr is not a valid part of the user address space\n");
break;
case WSAEINTR:
printf("A blocking Windows Sockets 1.1 call was canceled through WSACancelBlockingCall.\n");
break;
case WSAEINPROGRESS:
printf("A blocking Windows Sockets 1.1 call is in progress, or the service provider is still processing a callback function.\n");
break;
case WSAEINVAL:
printf("The listen function was not invoked prior to accept.\n");
break;
case WSAEMFILE:
printf("The queue is nonempty upon entry to accept and there are no descriptors available\n");
break;
case WSAENOBUFS:
printf("No buffer space is available.\n");
break;
case WSAENOTSOCK:
printf("The descriptor is not a socket\n");
break;
case WSAEOPNOTSUPP:
printf("The referenced socket is not a type that supports connection-oriented service.\n");
break;
case WSAEWOULDBLOCK:
printf("The socket is marked as nonblocking and no connections are present to be accepted\n");
break;
default:
printf("a unknown error eccured\n");
break;
}
//Sleep(100);
}
else
{
//inet_ntoa()函数将ipv4 internet地址转换为char far *
j = i;
printf("We successfully got a connection from %s:%d.\n",inet_ntoa(Clientaddr.sin_addr), ntohs(Clientaddr.sin_port));
hThd[i] = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)&ProceData,(LPVOID)&j,0,(PULONG)&nThd);
i++;
}
}


Ret = GetTickCount();
Sleep(90000000000000);
//释放空间
for (int k = 0; k < i; k++)
{
if (hThd[k] != NULL)
CloseHandle(hThd[k]);
if (NewSocket[k] != INVALID_SOCKET)
closesocket(NewSocket[k]);
}
Ret = GetTickCount() - Ret;
printf("The thread has been in %d seconds\n",Ret);
printf("over\n");


//关闭winsock
WSACleanup();
return 0;
}


先提出问题如下:
一:本来想在createthread()时,将第三个参数直接赋值为NewSocket[i],但是总提示参数不匹配,只好将其下标传过去,并将NewSocket[i]定义成了全局变量,不知道该如何解决??
二:在发送端如果发送的字符中包含空格,则空格后面的字符都收不到??
三:如果启十个客户端并频繁的发送数据,会出现丢包,即收到的数据为空??
四:主线程不知道该如何控制子线程,感知它的存在与否?
五:若客户端close一个,服务器怎么知道,并释放相应的空间?
六:第一次写这方面的东西,处理方法上一定有很多不合理的地方,望指点一下。


呵呵,提的问题太多了,若哪位高手有完美的代码,不吝赐教吧。多谢了!!

...全文
51 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
mechgoukiteng 2004-03-30
  • 打赏
  • 举报
回复
http://www.cs.wustl.edu/~schmidt/ACE.html
byybyybyy 2004-03-30
  • 打赏
  • 举报
回复
能说一下ACE是什么吗?见笑了!
Bruceleexiaokan 2004-03-30
  • 打赏
  • 举报
回复
即使是象这样简单的例子,ACE实现也更短,更安全。
zhengstar说的很是中肯了。另外,就搂主这种控制线程的方法,特别在主
线程退出时,想不内存泄漏都难呀!
sharkhuang 2004-03-29
  • 打赏
  • 举报
回复
没的要用ACE吧!这么简单的东西.
mechgoukiteng 2004-03-29
  • 打赏
  • 举报
回复
可以参考ACE 呵呵
zhengstar 2004-03-29
  • 打赏
  • 举报
回复
你的框架问题太大了。
其实这些东西很简单:
1.socket的handle放到一个链表中,用链表维护,起工作线程时直接把结构传入就行了。(保存socket的结构可以保存一个标志,表示socket的或线程的状态)
2.在工作线程中只管处理传进来的socket结构,令如果socket被对方关闭,根据recv返回值你这边是可以判断的。工作线程处理完后把结构中的线程状态标志一下
3.在主线程中,accept一个socket后,就new一个保存socket的结构,并把结构传给工作线程,同时挂链。
4.开一定时器,定时维护链表,发现结构中状态表示为线程结束,就删除该结构。

注:程序中注意几点:
1.开线程时不要用createthread,容易内存泄漏,用beginthreadex
2.维护链表时注意临届区

}

24,854

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 工具平台和程序库
社区管理员
  • 工具平台和程序库社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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