Windows环境下C++多线程TCP通信

原创 2017年04月30日 12:16:11

最近突然对传输层的东西有了兴趣...发现自己虽然学过计网也学过C++,却没有真正实现过客户端和服务器之间的通信,于是恶补了一下socket知识,再加上大佬们的指导,模仿着写了个demo...

直接上代码。

首先是服务器端,要注意如果一开始写了using namespace std; 那么就要注意std里面的bind和socket相关的bind是同名的...如果直接调用bind,实际上调用的是std::bind,而不是socket的bind方法。解决途径是调用::bind,感谢万能的StackOverflow...

因为这个问题我昨晚调试到半夜三点依然没解决...同时也感谢cao大佬的耐心指导,顺便贴个友链:http://showlinkroom.me/

Sever代码如下:

#include "stdafx.h"
#include <WinSock2.h> //windows socket的头文件
#include <Windows.h>
#include <iostream>
#include <thread>
#include <mutex>
#include <process.h>

#pragma comment(lib, "ws2_32.lib") //连接winsock2.h的静态库文件

using namespace std;

mutex m;

//定义结构体用来设置
typedef struct my_file
{
	SOCKET clientSocket; //文件内部包含了一个SOCKET 用于和客户端进行通信
	sockaddr_in clientAddr; //用于保存客户端的socket地址
	int id; //文件块的序号
}F;

DWORD WINAPI transmmit(const LPVOID arg)
{
	//实际上这里为了追求并发性不应该加锁,上锁是为了方便看输出
	m.lock();

	F *temp = (F*)arg;
	//获取文件的序号
	//int file_id = temp->id;
	//获取客户机的端口号
	//ntohs(temp -> clientAddr.sin_port); 
	cout << "测试开始,等待客户端发送消息..." << endl;
	//从客户端处接受数据
	char Buffer[MAXBYTE] = { 0 }; //缓冲区
	recv(temp->clientSocket, Buffer, MAXBYTE, 0); //recv方法 从客户端通过clientScocket接收
	cout << "线程" << temp->id << "从客户端的" << ntohs(temp->clientAddr.sin_port) << "号端口收到:" << Buffer << endl;

	//发送简单的字符串到客户端
	const char* s = "Server file";
	send(temp->clientSocket, s, strlen(s)*sizeof(char)+1, NULL);
	cout << "线程" << temp->id << "通过客户端的" << ntohs(temp->clientAddr.sin_port) << "号端口发送:" << s << endl;

	m.unlock();

	return 0;
}



int main()
{
	WSADATA wsaData;
	//第一个参数是winsocket load的版本号(2.2)
	WSAStartup(MAKEWORD(2, 3), &wsaData);
	//创建服务器端的socket(协议族, sokcet类型)
	SOCKET servSocket = socket(AF_INET, SOCK_STREAM, 0);//如果改成SOCK_DGRAM则使用UDP
	sockaddr_in servAddr; //服务器的socket地址,包含sin_addr表示IP地址,sin_port保持端口号和sin_zero填充字节
	memset(&servAddr, 0, sizeof(SOCKADDR)); //初始化socket地址
	servAddr.sin_family = PF_INET; //设置使用的协议族
	servAddr.sin_port = htons(2017); //设置使用的端口
	servAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); //define s_addr = S_un.S_addr
	::bind(servSocket, (SOCKADDR *)&servAddr, sizeof(SOCKADDR)); //将之前创建的servSocket和端口,IP地址绑定

	HANDLE hThread[20]; //获取句柄
	listen(servSocket, 20); //监听服务器端口
	for (int i = 0; i < 20; i++)
	{
		F *temp = new F; //创建新的传输结构体
		sockaddr_in clntAddr;
		int nSize = sizeof(SOCKADDR);
		SOCKET clientSock = accept(servSocket, (SOCKADDR*)&clntAddr, &nSize);
		//temp数据成员赋值
		temp->clientSocket = clientSock;
		temp->id = i + 1;
		temp->clientAddr = clntAddr;
		//通过句柄创建子线程
		hThread[i] = CreateThread(NULL, 0, &transmmit, temp, 0, NULL);
	}
	//等待子线程完成
	WaitForMultipleObjects(20, hThread, TRUE, INFINITE);
	cout << WSAGetLastError() << endl; //查看错误信息

	//关闭socket,释放winsock
	closesocket(servSocket);
	WSACleanup();

	cout << "服务器连接已关闭。" << endl;
	system("pause");

	return 0;
}

注意bind之后要监听(listen),并且accpet请求队列中的socket以建立连接。

大概流程就是bind -> listen -> if someone connects -> accept,如果是UDP就可以省略listen和accept(这两个分别是监听和接受新连接,然而UDP并不需要建立连接),直接收发(sendto和recvfrom)。


客户端则只需要创建一个socket,填写好地址信息,通过connect发送连接请求,之后就可以send或者recv了。如果是UDP则直接sendto和recvfrom,不需要connect(UDP无连接)。

Client代码:

#include "stdafx.h"
#include <WinSock2.h> //windows socket的头文件
#include <Windows.h>
#include <iostream>
#include <thread>
#include <process.h>

#pragma comment(lib, "ws2_32.lib") //连接winsock2.h的静态库文件

using namespace std;

int main()
{
	//加载winsock库
	WSADATA wsadata;
	WSAStartup(MAKEWORD(2, 3), &wsadata);

	//客户端socket
	SOCKET clientSock = socket(PF_INET, SOCK_STREAM, 0);
	//初始化socket信息
	sockaddr_in clientAddr;
	memset(&clientAddr, 0, sizeof(SOCKADDR));
	//clientAddr.sin_addr.s_addr = htonl(INADDR_ANY);
	clientAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
	clientAddr.sin_family = PF_INET;
	clientAddr.sin_port = htons(2017);
	//建立连接
	connect(clientSock, (SOCKADDR*)&clientAddr, sizeof(SOCKADDR));

	cout << "已建立连接。" << endl;

	char* s = new char[100];
	cout << "请输入你要发送的文字消息: ";
	cin >> s;
	send(clientSock, s, strlen(s)*sizeof(char) + 1, NULL);
	cout << "已发送:" << s << endl;

	system("pause");
	char Buffer[MAXBYTE] = { 0 };
	recv(clientSock, Buffer, MAXBYTE, 0);

	cout << "通过端口:" << ntohs(clientAddr.sin_port) << "接收到:" << Buffer << endl;
	
	closesocket(clientSock);
	WSACleanup();

	cout << "客户端连接已关闭。" << endl;
	system("pause");

	return 0;
}
这里将TCP最大监听连接数设置成了20,最多可以同时接受20个连接请求。

这里实现的只是最基础的字符串传输,之后还要实现文件传输...Orz



版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sinat_23118323/article/details/71006073

实现服务器端的多线程SOCKET Server C++/VC

想要实现的功能:在服务器端有一个控制台程序(或者Windows服务),与多个客户端程序通讯,其中主线程有一个socket绑定在一个固定端口上,负责监听客户端的Socket信息。每当启动一个客户端程序,...
  • chence19871
  • chence19871
  • 2015-03-02 16:08:18
  • 3603

多线程套接字编程-----程序实例(C++实现)

一.程序介绍 该程序主要包括以下内容: 1.多线程程序设计的一般框架,新线程负责循环接收网络数据,一旦收到网络数据就交由主线程处理;主线程负责循环处理网络数据。 2.(UDP)套接字编程的一般框...
  • chw1989
  • chw1989
  • 2012-04-12 12:54:27
  • 11945

Windows下基于socket多线程并发通信的实现

本文介绍了在Windows 操作系统下基于TCP/IP 协议Socket 套接口的通信机制以及多线程编程知识与技巧,并给出多线程方式实现多用户与服务端(C/S)并发通信模型的详细算法,最后展现了用C+...
  • xy010902100449
  • xy010902100449
  • 2015-04-07 14:54:44
  • 15349

C++多线程SOCKET收发

  • 2014年07月08日 16:47
  • 2KB
  • 下载

C++多线程socket系统新编

server-socket #include "stdafx.h" #include "winsock2.h" #include #include #include #include #inc...
  • wyansai
  • wyansai
  • 2016-02-28 23:16:26
  • 2426

C++多线程网络编程Socket实例.zip

  • 2009年02月17日 19:17
  • 47KB
  • 下载

C++ Socket 多线程

client.cpp************************/#include #include #pragma comment(lib, "ws2_32")#define LEN      ...
  • xinxijisuan
  • xinxijisuan
  • 2011-03-07 00:20:00
  • 6193

C++ socket 多线程服务器端

  • 2011年03月04日 16:25
  • 5KB
  • 下载

c++ socket 服务器 线程池 海量 并发 windoes linux 源代码 SPServer

http://blog.sina.com.cn/s/blog_6294abe701011tyl.html 对socket服务器海量并发比较感兴趣,从网上搜了一些材料,和大家分享一...
  • oMingZi12345678
  • oMingZi12345678
  • 2015-06-23 23:26:13
  • 1884

C++ 对于socket 多线程的运用

C++对多线程的简单入门理解
  • xiaoxiao_manong
  • xiaoxiao_manong
  • 2017-12-27 18:32:07
  • 170
收藏助手
不良信息举报
您举报文章:Windows环境下C++多线程TCP通信
举报原因:
原因补充:

(最多只允许输入30个字)