阻塞模式下socket多线程通信
来源:互联网 发布:淘宝怎么报名活动 编辑:程序博客网 时间:2024/06/01 07:51
客户端创建线程负责收发数据,其余操作封装在函数中,方便其他应用程序调用。服务端创建了两个线程,一个用于收发数据,对于接收连接accept部分开一个线程,这样主窗口就不会因阻塞而挂掉。( 参考资料:《Windows API开发详解——函数、接口、编程实例》第十四章)
客户端client.c
/* 头文件 */#include <stdio.h>#include "winsock2.h"#include <conio.h>/* 常量 */#define RECV_BUFFER_SIZE 8192// 变量定义SOCKADDR_IN clientService;// 地址SOCKET ConnectSocket;// socketWSADATA wsaData;// 库HANDLE hThread;char sendbuf[32] = "get information";// 默认发送的数据void SendStr(LPSTR sendbuf,SOCKET socket1);void InitSocket();void CreateMyThread();DWORD WINAPI CommunicationThread(LPVOID lpParameter);/************************************** CommunicationThread* 功能用于接收和发送数据的线程*为每一个连接的客户端创建一个接收发送数据的线程,*可以使用多个客户端同时连接到服务端* 参数lpParameter,SOKCET**************************************/DWORD WINAPI CommunicationThread(LPVOID lpParameter){// 获得参数sokcetSOCKET socket = (SOCKET)lpParameter;// 为接收数据分配空间LPSTR szRequest = HeapAlloc(GetProcessHeap(),0,RECV_BUFFER_SIZE);int iResult = 0;int bytesSent;// 用于保存send的返回值,实际发送的数据的大小while(1){// 接收数据iResult = recv(socket, // socketszRequest, // 接收缓存RECV_BUFFER_SIZE, // 缓存大小0);// 标志if (iResult == 0)// 接收数据失败,连接已经关闭{printf("Connection closing...\n");HeapFree(GetProcessHeap(), 0 ,szRequest);closesocket(socket);return 1;}else if (iResult == SOCKET_ERROR)// 接收数据失败,socket错误{printf("recv failed: %d\n", WSAGetLastError());HeapFree(GetProcessHeap(), 0 ,szRequest);closesocket(socket);return 1;}else if (iResult > 0) // 接收数据成功{// 显示接收到的数据printf("Bytes received: %d\tContent: %s\n",iResult,szRequest);// 如果接收到的数据是"download file"if (lstrcmpi(szRequest, "start listen") == 0){SendStr("COMING",socket);}// 如果接收到的数据是"get information"else if (lstrcmpi(szRequest, "YEAH") == 0){SendStr("123",socket);}else// 收到未知数据{printf ("unreferenced request\n");}}}// 释放接收数据缓存,关闭socketHeapFree(GetProcessHeap(), 0 ,szRequest);closesocket(socket);return 0;}/************************************** main* 功能 socket通信客户端**************************************/void main(int argc, char* argv[]){InitSocket();CreateMyThread();SendStr("request listen",ConnectSocket);getch();WaitForSingleObject( hThread, // handle to mutexINFINITE); // no time-out intervalWSACleanup();return;}void InitSocket(){// 初始化socket库,保存ws2_32.dll已经加载int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);if (iResult != NO_ERROR)printf("Error at WSAStartup()\n");// 创建socketConnectSocket = socket(AF_INET, // IPv4SOCK_STREAM, // 顺序的、可靠的、基于连接的、双向的数据流通信IPPROTO_TCP// 使用TCP协议);if (ConnectSocket == INVALID_SOCKET){printf("Error at socket(): %ld\n", WSAGetLastError());WSACleanup();return;}// 设置服务端的通信协议、IP地址、端口clientService.sin_family = AF_INET;clientService.sin_addr.s_addr = inet_addr( "222.31.66.209" );clientService.sin_port = htons( 10000 );// 连接到服务端if ( connect(ConnectSocket, // socket(SOCKADDR*) &clientService, // 地址sizeof(clientService) // 地址的大小) == SOCKET_ERROR){printf( "Failed to connect(%d)\n",WSAGetLastError() );WSACleanup();return;}}void SendStr(LPSTR sendbuf,SOCKET socket1){int bytesSent;// 准备发送数据// 如果输入参数是-d,那么发送的数据是“download file”否则是"get information"// 向服务端发送数据bytesSent = send( socket1, // socketsendbuf,// 发送的数据 lstrlen(sendbuf)+1,// 数据长度0 );// 无标志if(bytesSent == SOCKET_ERROR){printf( "send error (%d)\n", WSAGetLastError());closesocket(socket1);return;}printf( "Bytes Sent: %ld\t Content: %s\n", bytesSent,sendbuf);}void CreateMyThread(){// 为每一个连接创建一个数据发送的接收线程,// 使服务端又可以立即接收其他客户端的连接hThread = CreateThread(NULL,0,CommunicationThread, // 线程函数(LPVOID)ConnectSocket, // 将socket作为参数0,NULL);if(!hThread){printf("Create Thread error (%d)", GetLastError());}}
服务端 server.c
/* 头文件 */#include <winsock2.h>#include <ws2tcpip.h>#include <stdio.h>/* 常量 */#define DEFAULT_PORT "10000" // 端口#define MAX_REQUEST 1024 // 接收数据的缓存大小#define BUF_SIZE 4096 // 发送数据的缓存大小WSADATA wsaData;SOCKET ListenSocket = INVALID_SOCKET;// 监听socketSOCKET ClientSocket = INVALID_SOCKET;// 连接socketstruct addrinfo *result = NULL,hints;int iResult;// 保存返回结果void InitSocket();DWORD WINAPI AcceptThead();void SendStr(LPSTR sendbuf,SOCKET socket);/************************************** CommunicationThread* 功能用于接收和发送数据的线程*为每一个连接的客户端创建一个接收发送数据的线程,*可以使用多个客户端同时连接到服务端* 参数lpParameter,SOKCET**************************************/DWORD WINAPI CommunicationThread(LPVOID lpParameter){// 获得参数sokcetSOCKET socket = (SOCKET)lpParameter;// 为接收数据分配空间LPSTR szRequest = HeapAlloc(GetProcessHeap(),0, MAX_REQUEST);int iResult;int bytesSent;// 用于保存send的返回值,实际发送的数据的大小while(1){// 接收数据iResult = recv(socket, // socketszRequest, // 接收缓存MAX_REQUEST, // 缓存大小0);// 标志if (iResult == 0)// 接收数据失败,连接已经关闭{printf("Connection closing...\n");HeapFree(GetProcessHeap(), 0 ,szRequest);closesocket(socket);return 1;}else if (iResult == SOCKET_ERROR)// 接收数据失败,socket错误{printf("recv failed: %d\n", WSAGetLastError());HeapFree(GetProcessHeap(), 0 ,szRequest);closesocket(socket);return 1;}else if (iResult > 0) // 接收数据成功{// 显示接收到的数据printf("Bytes received: %d\tContent: %s\n",iResult, szRequest);// 如果接收到的数据是"download file"if (lstrcmpi(szRequest, "request listen") == 0){SendStr("start listen",socket);}// 如果接收到的数据是"get information"else if (lstrcmpi(szRequest, "COMING") == 0){// 发送数据SendStr("YEAH",socket);}else if (lstrcmpi(szRequest, "123") == 0){SendStr("333",socket);}else if (lstrcmpi(szRequest, "close") == 0){break;}else// 收到未知数据{printf ("unreferenced request\n");}}}// 释放接收数据缓存,关闭socketHeapFree(GetProcessHeap(), 0 ,szRequest);closesocket(socket);return 0;}/************************************** int __cdecl main(void)* 功能socket服务端**************************************/int __cdecl main(void){InitSocket();AcceptThead();// 循环退出,释放DLL。WSACleanup();return 0;}void InitSocket(){// 初始化Winsock,保证Ws2_32.dll已经加载iResult = WSAStartup(MAKEWORD(2,2), &wsaData);if (iResult != 0){printf("WSAStartup failed: %d\n", iResult);return 1;}// 地址ZeroMemory(&hints, sizeof(hints));hints.ai_family = AF_INET;hints.ai_socktype = SOCK_STREAM;hints.ai_protocol = IPPROTO_TCP;hints.ai_flags = AI_PASSIVE;// 获取主机地址,保证网络协议可用等iResult = getaddrinfo(NULL, // 本机DEFAULT_PORT, // 端口&hints, // 使用的网络协议,连接类型等&result);// 结果if ( iResult != 0 ){printf("getaddrinfo failed: %d\n", iResult);WSACleanup();return 1;}// 创建socket,用于监听ListenSocket = socket(result->ai_family, // 网络协议,AF_INET,IPv4result->ai_socktype, // 类型,SOCK_STREAMresult->ai_protocol);// 通信协议,TCPif (ListenSocket == INVALID_SOCKET){printf("socket failed: %ld\n", WSAGetLastError());freeaddrinfo(result);WSACleanup();return 1;}// 绑定到端口iResult = bind( ListenSocket, result->ai_addr, (int)result->ai_addrlen);if (iResult == SOCKET_ERROR){printf("bind failed: %d\n", WSAGetLastError());freeaddrinfo(result);closesocket(ListenSocket);WSACleanup();return 1;}printf("bind\n");freeaddrinfo(result);// reuslt不再使用// 开始监听iResult = listen(ListenSocket, SOMAXCONN);printf("start listen......\n");if (iResult == SOCKET_ERROR){printf("listen failed: %d\n", WSAGetLastError());closesocket(ListenSocket);WSACleanup();return 1;}if(!CreateThread(NULL,0,AcceptThead, // 线程函数(LPVOID)ClientSocket, // 将socket作为参数0,NULL)){printf("Create Thread error (%d)", GetLastError());}}DWORD WINAPI AcceptThead(){while (1){// 接收客户端的连接,accept函数会等待,直到连接建立printf("ready to accept\n");ClientSocket = accept(ListenSocket, NULL, NULL);// accept函数返回,说明已经有客户端连接// 返回连接socketprintf("accept a connetion\n");if (ClientSocket == INVALID_SOCKET){printf("accept failed: %d\n", WSAGetLastError());closesocket(ListenSocket);break;// 等待连接错误,退出循环}// 为每一个连接创建一个数据发送的接收线程,// 使服务端又可以立即接收其他客户端的连接if(!CreateThread(NULL,0,CommunicationThread, // 线程函数(LPVOID)ClientSocket, // 将socket作为参数0,NULL)){printf("Create Thread error (%d)", GetLastError());break;}}}void SendStr(LPSTR sendbuf,SOCKET socket){int bytesSent;// 准备发送数据// 如果输入参数是-d,那么发送的数据是“download file”否则是"get information"// 向服务端发送数据bytesSent = send( socket, // socketsendbuf,// 发送的数据 lstrlen(sendbuf)+1,// 数据长度0 );// 无标志if(bytesSent == SOCKET_ERROR){printf( "send error (%d)\n", WSAGetLastError());closesocket(socket);return;}printf( "Bytes Sent: %ld\tContent: %s\n", bytesSent,sendbuf );}
- 阻塞模式下socket多线程通信
- Linux下基于socket多线程并发通信的实现 阻塞
- socket通信下 阻塞与非阻塞
- UE4 Socket多线程非阻塞通信【1】
- UE4 Socket多线程非阻塞通信【2】
- linux 下socket编程 一对一阻塞通信
- socket异步通信-非阻塞模式(异步非阻塞)
- VC下SOCKET通信,设置非阻塞模式,添加心跳检查
- linux下socket编程 select实现非阻塞模式多台客户端与服务器通信
- socket通信阻塞模式下,设置发送和接受函数超时
- Linux下socket阻塞模式与非阻塞模式
- Java Socket学习---nio实现阻塞多线程通信
- linux socket非阻塞模式下笔记
- java socket通信I/O阻塞>多线程实现非阻塞通信
- socket异步通信__如何设置成非阻塞模式、非阻塞模式下判断connect成功(失败)、判断recv/recvfrom成功(失败)、判断send/sendto成功(失败)
- socket异步通信:如何设置成非阻塞模式,非阻塞模式下判断connect成功(失败),判断recv/recvfrom成功(失败),判断send/sendto
- socket异步通信-如何设置成非阻塞模式、非阻塞模式下判断connect成功(失败)、判断recv/recvfrom成功(失败)、判断send/sendto
- Socket通信(TCP)非阻塞模式-select模型
- STL中查找算法(13个)
- 个人认为是目前最完善的C++及相关领域的书架
- JAVA程序员之路
- 详解QT源码之QT创建窗口程序、消息循环和WinMain函数
- Java开发中的23种设计模式
- 阻塞模式下socket多线程通信
- Hibernate关联映射之多对多单/双向关联映射
- linux下tree命令详解
- JAVA程序员之路
- 数据结构之单链表的实现
- shell的算术运算总结
- gdb 条件断点
- COnlyServerDlg::COnlyServerDlg
- 2006年百度之星程序设计大赛试题初赛题目-题3-变态的比赛规则