版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/youkawa/article/details/7577972
客户端创建线程负责收发数据,其余操作封装在函数中,方便其他应用程序调用。服务端创建了两个线程,一个用于收发数据,对于接收连接accept部分开一个线程,这样主窗口就不会因阻塞而挂掉。( 参考资料:《Windows API开发详解——函数、接口、编程实例》第十四章)
客户端client.c
/* 头文件 */
#include <stdio.h>
#include "winsock2.h"
#include <conio.h>
/* 常量 */
#define RECV_BUFFER_SIZE 8192
// 变量定义
SOCKADDR_IN clientService;// 地址
SOCKET ConnectSocket;// socket
WSADATA 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
)
{
// 获得参数sokcet
SOCKET socket = (SOCKET)lpParameter;
// 为接收数据分配空间
LPSTR szRequest = HeapAlloc(GetProcessHeap(),0,RECV_BUFFER_SIZE);
int iResult = 0;
int bytesSent;// 用于保存send的返回值,实际发送的数据的大小
while(1)
{
// 接收数据
iResult = recv(socket, // socket
szRequest, // 接收缓存
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");
}
}
}
// 释放接收数据缓存,关闭socket
HeapFree(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 mutex
INFINITE); // no time-out interval
WSACleanup();
return;
}
void InitSocket()
{
// 初始化socket库, 保存ws2_32.dll已经加载
int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != NO_ERROR)
printf("Error at WSAStartup()\n");
// 创建socket
ConnectSocket = socket(AF_INET, // IPv4
SOCK_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, // socket
sendbuf,// 发送的数据
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;// 监听socket
SOCKET ClientSocket = INVALID_SOCKET;// 连接socket
struct 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
)
{
// 获得参数sokcet
SOCKET socket = (SOCKET)lpParameter;
// 为接收数据分配空间
LPSTR szRequest = HeapAlloc(GetProcessHeap(),0, MAX_REQUEST);
int iResult;
int bytesSent;// 用于保存send的返回值,实际发送的数据的大小
while(1)
{
// 接收数据
iResult = recv(socket, // socket
szRequest, // 接收缓存
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");
}
}
}
// 释放接收数据缓存,关闭socket
HeapFree(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,IPv4
result->ai_socktype, // 类型,SOCK_STREAM
result->ai_protocol);// 通信协议,TCP
if (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函数返回,说明已经有客户端连接
// 返回连接socket
printf("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, // socket
sendbuf,// 发送的数据
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 );
}