孕妇梦见黑狗跟着自己:C/S 多线程Socket类
来源:百度文库 编辑:中财网 时间:2024/05/04 18:33:04
C/S模式
客户机/服务器模式的建立基于以下两点:首先,建立网络的起因是网络中软硬件资源、运算能力和信息不均等,需要共享,从而造就拥有众多资源的主机提供服务,资源较少的客户请求服务这一非对等作用。其次,网间进程通信完全是异步的,相互通信的进程间既不存在父子关系,又不共享内存缓冲区,因此需要一种机制为希望通信的进程间建立联系,为二者的数据交换提供同步,这就是基于客户机/服务器模式的TCP/IP。 客户机/服务器模式在操作过程中采取的是主动请求的方式。基于TCP(面向连接)的socket编程 服务端进程通过bind方法将其套接字告知系统,以使其他的套接字能找到它。它可通过套接字的“侦听(listen)”来“接收(accept)”发过来的信息。客户端的进程同服务端套接字建立连接然后交换信息。需要的信息都可以从该通道向任一端进行发送。面向连接的TCP通信过程如下:
服务器: 创建端点 (socket()) 绑定地址(bind()) 指定队列(listen()) 等待连接 (accept()) 传输数据 (read()/write()) 客户端: 创建端点 (socket()) 链接服务器 (connect()) 传输数据(read()/write()) 基于UDP(面向无连接)的socket编程 用无连接协议,双方的套接字都需要用bind方法来告知系统。这是因为每方的信息都会单独处理,所以每次服务端发信息过来时,客户端都需要找到它,反之亦然。每次调用bind方法,都绑定了一个新的端口。当然,如果端口已经被使用了,则是不能被绑定的。如果你指定的端口为0,则系统会把当前可用的端口自动给你一个。由于发送信息的额外任务,进程不会使用read/write方法,而是使用recvfrom/sendto方法。这两个方法的参数一个是要写入的套接字,另一个则是远程计算机上服务的地址。 服务端: 创建端点(socket()) 绑定地址 (bind()) 传输数据(sendto()/recvfrom()) 客户端: 创建端点 (socket()) 绑定地址(bind()) (connect方法可选择调用) 连接服务端(connect()) 传输数据(sendto()/recvfrom()) 多线程的设计 《VC中利用多线程技术实现线程之间的通信》这篇文章比较适合线程的了解,Win32 提供了一系列的API函数来完成线程的创建、挂起、恢复、终结以及通信等工作。MFC中使用线程要注意: 1、尽量少的使用全局变量、static变量做共享数据,尽量使用参数传递对象。 2、在MFC中请慎用线程。因为MFC的框架假定你的消息处理都是在主线程中完成的。首先窗口句柄是属于线程的,如果拥有窗口句柄的线程退出了,如果另一个线程处理这个窗口句柄,系统就会出现问题。而MFC为了避免这种情况的发生,使你在子线程中调用消息(窗口)处理函数时,就会不停的出Assert错误,烦都烦死你。典型的例子就时CSocket,因为CSocket是使用了一个隐藏窗口实现了假阻塞,所以不可避免的使用了消息处理函数,如果你在子线程中使用CSocket,你就可能看到assert的弹出了。 3、不要在不同的线程中同时注册COM组件。常见问题的解决1、关闭套接字 我们在利用IOCP(完成端口)进行程序设计的时候,经常要关闭一些不满足条件的套接字。假如我们直接采用closesocket方法进行关闭的话,绑定到IO端口的此套接字的未发送的数据就会丢失,这种情况是我们不愿意发生的。下面介绍一种合理关闭此套接字的方法:
首先,利用setsockopt(MSDN)函数设定套接字的选项,我们把此套接字设定为:假如有数据未发送,当数据发送完后再关闭此套接字。
代码如下:
LINGER lingerStruct;
lingerStruct.l_onoff = 1;
lingerStruct.l_linger = 0;
setsockopt(Socket, SOL_SOCKET, SO_LINGER,
(char *)&lingerStruct, sizeof(lingerStruct) );
// Now close the socket handle. This will do an abortive or graceful close, as requested.
CancelIo((HANDLE) Socket);
closesocket(Socket);
clientSocket = INVALID_SOCKET;
当在完成端口的数据被发送出去之后,套接字就会被关闭,这样我们就完成了一个套接字的关闭。 <参考 http://www.examda.com/ncre2/cpp/fudao/20090107/091252332.html> 2、解决 Socket API错误代码:WSAECONNRESET (10054) 出现原因:使用UDP SOCKET时(利用事件触发方式),如果发送端在发送数据时(WSASendTo),接收端没还有创建,那么发送端将会收到一个事件通知,此时调用WSARecv()函数时将会产生调用错误(WSAECONNRESET ),从这以后,这个发送端这个SOCKET无法接受到数据。解决办法: a.头文件中加入下面代码:
#include
#pragma comment(lib,"ws2_32.lib")
#define IOC_VENDOR 0x18000000
#define _WSAIOW(x,y) (IOC_IN|(x)|(y))
#define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR,12)
b.在创建socket之后加入下面代码:
DWORD dwBytesReturned = 0;
BOOL bNewBehavior = FALSE;
DWORD status;
status = WSAIoctl(m_hSock, SIO_UDP_CONNRESET,
&bNewBehavior,
sizeof (bNewBehavior),
NULL, 0, &dwBytesReturned,
NULL, NULL);
<参考 http://blog.csdn.net/wupangzi/archive/2009/07/27/4384081.aspx及http://hi.baidu.com/jetqu2003/blog/item/397700031435e9703812bbcc.html>
客户机/服务器模式的建立基于以下两点:首先,建立网络的起因是网络中软硬件资源、运算能力和信息不均等,需要共享,从而造就拥有众多资源的主机提供服务,资源较少的客户请求服务这一非对等作用。其次,网间进程通信完全是异步的,相互通信的进程间既不存在父子关系,又不共享内存缓冲区,因此需要一种机制为希望通信的进程间建立联系,为二者的数据交换提供同步,这就是基于客户机/服务器模式的TCP/IP。 客户机/服务器模式在操作过程中采取的是主动请求的方式。基于TCP(面向连接)的socket编程 服务端进程通过bind方法将其套接字告知系统,以使其他的套接字能找到它。它可通过套接字的“侦听(listen)”来“接收(accept)”发过来的信息。客户端的进程同服务端套接字建立连接然后交换信息。需要的信息都可以从该通道向任一端进行发送。面向连接的TCP通信过程如下:
服务器: 创建端点 (socket()) 绑定地址(bind()) 指定队列(listen()) 等待连接 (accept()) 传输数据 (read()/write()) 客户端: 创建端点 (socket()) 链接服务器 (connect()) 传输数据(read()/write()) 基于UDP(面向无连接)的socket编程 用无连接协议,双方的套接字都需要用bind方法来告知系统。这是因为每方的信息都会单独处理,所以每次服务端发信息过来时,客户端都需要找到它,反之亦然。每次调用bind方法,都绑定了一个新的端口。当然,如果端口已经被使用了,则是不能被绑定的。如果你指定的端口为0,则系统会把当前可用的端口自动给你一个。由于发送信息的额外任务,进程不会使用read/write方法,而是使用recvfrom/sendto方法。这两个方法的参数一个是要写入的套接字,另一个则是远程计算机上服务的地址。 服务端: 创建端点(socket()) 绑定地址 (bind()) 传输数据(sendto()/recvfrom()) 客户端: 创建端点 (socket()) 绑定地址(bind()) (connect方法可选择调用) 连接服务端(connect()) 传输数据(sendto()/recvfrom()) 多线程的设计 《VC中利用多线程技术实现线程之间的通信》这篇文章比较适合线程的了解,Win32 提供了一系列的API函数来完成线程的创建、挂起、恢复、终结以及通信等工作。MFC中使用线程要注意: 1、尽量少的使用全局变量、static变量做共享数据,尽量使用参数传递对象。 2、在MFC中请慎用线程。因为MFC的框架假定你的消息处理都是在主线程中完成的。首先窗口句柄是属于线程的,如果拥有窗口句柄的线程退出了,如果另一个线程处理这个窗口句柄,系统就会出现问题。而MFC为了避免这种情况的发生,使你在子线程中调用消息(窗口)处理函数时,就会不停的出Assert错误,烦都烦死你。典型的例子就时CSocket,因为CSocket是使用了一个隐藏窗口实现了假阻塞,所以不可避免的使用了消息处理函数,如果你在子线程中使用CSocket,你就可能看到assert的弹出了。 3、不要在不同的线程中同时注册COM组件。常见问题的解决1、关闭套接字 我们在利用IOCP(完成端口)进行程序设计的时候,经常要关闭一些不满足条件的套接字。假如我们直接采用closesocket方法进行关闭的话,绑定到IO端口的此套接字的未发送的数据就会丢失,这种情况是我们不愿意发生的。下面介绍一种合理关闭此套接字的方法:
首先,利用setsockopt(MSDN)函数设定套接字的选项,我们把此套接字设定为:假如有数据未发送,当数据发送完后再关闭此套接字。
代码如下:
LINGER lingerStruct;
lingerStruct.l_onoff = 1;
lingerStruct.l_linger = 0;
setsockopt(Socket, SOL_SOCKET, SO_LINGER,
(char *)&lingerStruct, sizeof(lingerStruct) );
// Now close the socket handle. This will do an abortive or graceful close, as requested.
CancelIo((HANDLE) Socket);
closesocket(Socket);
clientSocket = INVALID_SOCKET;
当在完成端口的数据被发送出去之后,套接字就会被关闭,这样我们就完成了一个套接字的关闭。 <参考 http://www.examda.com/ncre2/cpp/fudao/20090107/091252332.html> 2、解决 Socket API错误代码:WSAECONNRESET (10054) 出现原因:使用UDP SOCKET时(利用事件触发方式),如果发送端在发送数据时(WSASendTo),接收端没还有创建,那么发送端将会收到一个事件通知,此时调用WSARecv()函数时将会产生调用错误(WSAECONNRESET ),从这以后,这个发送端这个SOCKET无法接受到数据。解决办法: a.头文件中加入下面代码:
#include
#pragma comment(lib,"ws2_32.lib")
#define IOC_VENDOR 0x18000000
#define _WSAIOW(x,y) (IOC_IN|(x)|(y))
#define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR,12)
b.在创建socket之后加入下面代码:
DWORD dwBytesReturned = 0;
BOOL bNewBehavior = FALSE;
DWORD status;
status = WSAIoctl(m_hSock, SIO_UDP_CONNRESET,
&bNewBehavior,
sizeof (bNewBehavior),
NULL, 0, &dwBytesReturned,
NULL, NULL);
<参考 http://blog.csdn.net/wupangzi/archive/2009/07/27/4384081.aspx及http://hi.baidu.com/jetqu2003/blog/item/397700031435e9703812bbcc.html>
socket 多线程的疑惑!新人问题
为什么多线程可以解决同一个socket的读写文件问题
为什么多线程可以解决同一个socket的读写文件问题
C语言 用定时器 模拟多线程
谁有socket多线程程序的代码???最简单例子就行~!!
求Java基于socket和多线程技术的聊天室程序源代码
多PC连接服务器问题[C#][Socket]
c#socket编程中遇到的问题
谁能帮我找一段c语言的socket程序?
niosII IDE c/c++ 不认识socket 怎么办啊?
tornado打开时出错 svctcp_.c -tcp socket creation problem
c语言socket.h头文件来源地址???
什么是C/S
S.C collection05
关于C S!
S/C是什么意思?
format c:/s
C.S.I有多小季?
c语言设计s
C/S, B/S是什么意思?
什么是C/S,什么是B/S ??
B/S、C/S
什么是B/S C/S
怎么用C编多线程程序啊/给个例子。送20分