c++多线程通信例子_第1页
c++多线程通信例子_第2页
c++多线程通信例子_第3页
c++多线程通信例子_第4页
c++多线程通信例子_第5页
已阅读5页,还剩4页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

关于 winsock 服务器和客户端编程 2008 年 12 月 28 日 星期日 23:22 在网络 编程中,最常用和最基础的就是 WINSOCK. 现在我们讨论 WINDOWS 下的 SOCKET 编程 . 大凡在 WIN32 平台上的 WINSOCK 编程都要经过下列步骤: 定义变量-获得 WINDOCK 版本-加载 WINSOCK 库-初始化-创建套 接字- 设置套接字选项-关闭套接字-卸载 WINSOCK 库-释放资源 下面介绍 WINSOCK C/S 的建立过程: 服务器 客户端 _ 1 初始化 WSA 1 初始化 WSA _ 2 建立一个 SOCKET 2 建立一个 SOCKET _ 3 绑定 SOCKET 3 连接到服务器 _ 4 在指定的端口监听 4 发送和接受数据 _ 5 接受一个连接 5 断开连接 _- 6 发送和接受数据 _ 7 断开连接 _ 大家注意,在 VC 中进行 WINSOCK 编程时,需要引入如下两个库文件: WINSOCK.H(这个是 WINSOCK API 的头文件,WIN2K 以上支持 WINSOCK2, 所以 可以用 WINSOCK2.H);Ws2_32.lib(WINSOCK API 连接库文件). 使用方式如下: #include #pragma comment(lib,“ws2_32.lib“) 下面我们通过具体的代码演示服务器和客户端的工作流程: 首先,建立一个 WSADATA 结构,通常用 wsaData WSADATA wsaData; 然后,调用 WSAStartup 函数,这个函数是连接应用程序与 winsock.dll 的第一个 调用.其中,第一个参数是 WINSOCK 版本号,第二个参数是指向 WSADATA 的指针.该函数返回一个 INT 型值,通过检查这个值来确定初始化是 否成功.调用格式如下:WSAStartup(MAKEWORD(2,2), /返回值不等与 0,说明初始化 失败 ExitProcess(); /退出程序 应用程序在完成对请求的 SOCKET 库使用后,要调用 WSACleanup 函数来接触 SOCKET 库的绑定 ,并且释放资源. 注意 WSAStartup 初始化后 ,必须建立一个 SOCKET 结构来保存 SOCKET 句柄. 下面我们建立一个 SOCKET. 首先我们建立一个 m_socket 的 SOCKET 句柄,接着调用 socket()函数,函数返 回值保存在 m_socket 中 .我们使用 AF_INFE,SOCK_STREAM,IPPROTO_TCP 三个参数.第一个表示地址族,AF_INFE 表示 TCP/IP 族, 第二个表示服务类型,在 WINSOCK2 中,SOCKET 支持以下三种类型; SOCK_STREAM 流式套接字 SOCK_DGRAM 数据报套接字 SOCK_RAW 原始套接字 第三个参数表示协议: IPPROTO_UDP UDP 协议 用于无连接数据报套接字 IPPROTO_TCP TCP 协议 用于流式套接字 IPPROTO_ICMP ICMP 协议用于原始套接字 m_socket=socket(AF_INFE,SOCK_STREAM,IPPROTO_TCP); /创建 TCP 协议 以下代码用于检查返回值是否有错误: if(m_scoket=INVALID_SOCKET) prinrf(“Error at socket():%dn“,GetLastError(); WSACleanup(); /释放资源 return; 说明,如果 socket()调用失败,他将返回 INVALID_SOCKET. 为了服务器能接受一个连接,他必须绑定一个网络地址 ,下面的代码展示如 何绑定一个已经初始化的 IP 和端口的 Socket.客户端程序用这个 IP 地址和端口来连接服务器. sockaddr_in service; service.sin_family=AF_INET; /INTERNET 地址族 service.sin_addr.s_addr=inet_addr(“127.0.0.1“); /将要绑定的本地 IP 地址 service.sin_port=htons(27015); /27015 将要绑定的端 口 下面我们调用 BIND 函数,把 SOCKET 和 SOCKADDR 以参数的形式传入,并检 查错误. if(bind(m_socket,(SOCKADDR*) closesocket(m_socket); return; 当绑定完成后,服务器必须建立一个监听队列,以接受客户端的请求.listen() 使服务器进入监听状态,该函数调用成功返回 0,否则返回 SOCKET_ERROR.代码如下: if(listen(m_socket,1)=SOCKET-ERROR) printf(“error listening on socket.n“); 服务器端调用完 LISTEN()后,如果此时客户端调用 CONNECT()函数,服务器端 必须在调用 ACCEPT().这样服务器和客户端才算正式完成通信程序的 连接动作. 一旦服务器开始监听,我们就要指定一个句柄来表示利用 ACCEPT()函数接受的 连接,这个句柄是用来发送和接受数据的表示.建立一个 SOCKET 句柄 Socket AcceptSocket 然后利用无限循环来检测是否有连接传入.一但有连接请 求,ACCEPT()函数就会被调用,并且返回这次连接的句柄 . printf(“waitong for a client to connect.n“); while(1) AcceptSocket=SOCKET_ERROR; while(AcceptSocket=SOCKET_ERROR) AcceptSocket=accept(m_socket,NULL,NULL); 下面看客户端端代码: sockaddr_in clientService; clientService.sin_family=AF_INET; /INTERNET 地 址族 clientService.sin_addr.s_addr=inet_addr(“127.0.0.1“); /将要绑定的本地 IP 地址 clientService.sin_port=htons(27015); /27015 将要绑 定的端口 下面调用 CONNECT()函数: if ( connect( m_socket, (SOCKADDR*) WSACleanup(); return; /如果调用失败清理退出 /调用成功继续读写数据 _ _ 到这里,服务器和客户端的基本流程介绍完毕,下面我们介绍数据交换. send(): int send SOCKET s, /指定发送端套接字 const char FAR?*buf, /指明一个存放应用程序要发送的数据的缓冲 区 int len, /实际要发送的数据字节数 int flags /一般设置为 0 ; C/S 都用 SEND 函数向 TCP 连接的另一端发送数据. recv(): int recv SOCKET s, /指定发送端套接字 char FAR?*buf, /指明一个缓冲区 存放 RECC 受到的数据 int len, /指明 BUF 的长度 int flags /一般设置为 0 ; C/S 都使用 RECV 函数从 TCP 连接的另一端接受数据 下面将完整的程序代码提供如下,大家可直接编译运行 首先看客户端的代码: #include #include #pragma comment(lib, “ws2_32.lib“) void main() / 初始化 Winsock. WSADATA wsaData; int iResult = WSAStartup( MAKEWORD(2,2), if ( iResult != NO_ERROR ) printf(“Error at WSAStartup()n“); / 建立 socket socket. SOCKET client; client = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ); if ( client = INVALID_SOCKET ) printf( “Error at socket(): %ldn“, WSAGetLastError() ); WSACleanup(); return; / 连接到服务器. sockaddr_in clientService; clientService.sin_family = AF_INET; clientService.sin_addr.s_addr = inet_addr( “127.0.0.1“ ); clientService.sin_port = htons( 27015 ); if ( connect( client, (SOCKADDR*) WSACleanup(); return; / 发送并接收数据. int bytesSent; int bytesRecv = SOCKET_ERROR; char sendbuf32 = “Client: Sending data.“; char recvbuf32 = “; bytesSent = send( client, sendbuf, strlen(sendbuf), 0 ); printf( “Bytes Sent: %ldn“, bytesSent ); while( bytesRecv = SOCKET_ERROR ) bytesRecv = recv( client, recvbuf, 32, 0 ); if ( bytesRecv = 0 | bytesRecv = WSAECONNRESET ) printf( “Connection Closed.n“); break; if (bytesRecv #include #pragma comment(lib, “ws2_32.lib“) void main() / 初始化 WSADATA wsaData; int iResult = WSAStartup( MAKEWORD(2,2), if ( iResult != NO_ERROR ) printf(“Error at WSAStartup()n“); / 建立 socket SOCKET server; server = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ); if ( server = INVALID_SOCKET ) printf( “Error at socket(): %ldn“, WSAGetLastError() ); WSACleanup(); return; / 绑定 socket sockaddr_in service; service.sin_family = AF_INET; service.sin_addr.s_addr = inet_addr( “127.0.0.1“ ); service.sin_port = htons( 27015 ); if ( bind( server, (SOCKADDR*) closesocket(server); return; / 监听 socket if ( listen( server, 1 ) = SOCKET_ERROR ) printf( “Error listening on socket.n“); / 接受连接 SOCKET AcceptSocket; printf( “Waiting for a client to connect.n“ ); while (1) AcceptSocket = SOCKET_ERROR; while ( AcceptSocket = SOCKET_ERROR ) AcceptSocket = accept( server, NULL, NULL ); printf( “Client Connected.n“); server = AcceptSocket; break; / 发送接受数据 int bytesSent; int bytesRecv = SOCKET_ERROR; char sendbuf32 = “Server: Sending Data.“; char recvbuf32 = “; bytesRecv = recv( server, recvbuf, 32, 0 ); printf( “Bytes Recv: %ldn“, bytesRecv ); bytesSent = send( server, sendbuf, strlen(sendbuf), 0 ); printf( “Bytes Sent: %ldn“, bytesSent ); return; 本程序仅仅描述了同步的情况! PS:本文转自百度贴吧新红盟吧 = =accept()补充 绑定 socket 后用 listen 函数去监听,如果有连接请求就把该请求放到等待队列 里,等待 accept 函数来接收。 一旦 accept 接收成功就创建一个新的 socket 来处理与 client 的通讯。 accept()函数 准备好了,系统调用 accept()会有点古怪的地方的! 你可以想象发生这样的事情:有人从很远的地方通过一个你在侦听(listen()的 端口连接(connect()到你的机器。 它的连接将加入到等待接受(accept()的队列中。你调用 accept()告诉它你有空 闲的连接。它将返回一个新的套接字文件描述符! 这样你就有两个套接字了,原来的一个还在侦听你的那个端口,新的在准备发 送(send()和接收(recv()数据。这就是这个过程! 函数是这样定义的: #include int accept(int sockfd, void *addr, int *addrlen); sockfd 相当简单,是和 isten()中一样的套接字描述符。addr 是个指向局部的数 据结构 sockaddr_in 的指针。 这是要求接入的信息所要去的地方(你可以测定哪个地址在哪个端口呼叫你)。 在它的地址传递给 accept 之前,addrlen 是个局部的整形变量,设置为 sizeof(struct sockaddr_in) accept 将不会将多余的字节给 addr。如果你放入的少些,那么它会通过改变 addrlen 的值反映出来。 同样,在错误时返回-1,并设置全局错误变量 errno。 现在是你应该熟悉的代码片段。 #include #include #include #define MYPORT 3490 /*用户接入端口*/ #define BACKLOG 10 /* 多少等待连接控制*/ main() int sockfd, new_fd; /* listen on sock_fd, new connection

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论