C++socket编程学习总结(1)(建立TCP服务器、并监听)

上次的两次面试,一位面试官认真的看了我的博客(十分感动),然后建议我好好复习下socket还有操作系统。感觉找工作好多都要求socket编程,于是我再预习复习一下。主要是当时这门课学校老师照本宣科,连代码都不讲,也很没意思,学生混老师也混。下面切入正题吧,我今天就复习这么多。

这是在WIN上创建socket,创建项目时使用win32控制台,要注意linux上是没有windows.h头文件的,所以这么写是不可以的。

#include <iostream>
#include<Windows.h>
using namespace std;

int main(int argc,char* argv[])
{
	//初始化动态链接库
	WSADATA ws;
	WSAStartup(MAKEWORD(2, 2), &ws);//22是版本号,加载动态链接库
	int sock = socket(AF_INET, SOCK_STREAM, 0);//AF_INET指明调用TCP/IP协议,SOCK_STREAM是TCP的协议(相对于UDP来讲)
	cout << sock << endl;//打印句柄id,失败返回负值
	//失败提示
	if (sock == -1)
	{
		cout << "create socket failed!" << endl;
		return -1;
	}
	closesocket(sock);//关闭连接

	return 0;
}

创建TCP服务器主要是建立结构体saddr,它是sockaddr_in类的,并绑定端口,使用bind:

#include <iostream>
#include<Windows.h>
using namespace std;

int main(int argc,char* argv[])
{
	//初始化动态链接库
	WSADATA ws;
	WSAStartup(MAKEWORD(2, 2), &ws);//22是版本号,加载动态链接库
	int sock = socket(AF_INET, SOCK_STREAM, 0);//AF_INET指明调用TCP/IP协议,SOCK_STREAM是TCP的协议(相对于UDP来讲)
	cout << sock << endl;//打印句柄id,失败返回负值
	//失败提示
	if (sock == -1)
	{
		cout << "create socket failed!" << endl;
		return -1;
	}

	//测试端口号
	unsigned short port = 8080;
	if (argc > 1)
	{
		port = atoi(argv[1]);
	}

	//创建TCP相关的结构体
	sockaddr_in saddr;
	saddr.sin_family = AF_INET;//使用TCP
	saddr.sin_port = htons(port);//本地字节序转网络字节序
	//X86架构是小端的而网络字节流是大端的,
	//Linux不一定,小型linux使用的也是和网路字节序一样的话转换也只是一个空的宏,
	//这时候会可有可无,但考虑兼容性要求建议加上
	saddr.sin_addr.s_addr = htonl(0);//这里可以指定网卡,0是任意的意思

	if (bind(sock, (sockaddr*)&saddr, sizeof(saddr)) != 0)//绑定端口号到上面创建的socket,并判断是否成功
	{
		cout << "bind port " << port << " failed!" << endl;
		return -2;
	}
	else
	{
		cout<< "bind port " << port << " success!" << endl;
	}
	closesocket(sock);//关闭连接

	return 0;
}

可以看到,系统资源足够是不会失败的:

接下来是监听listen和建立连接accept。我使用了telnet来测试,IP就是本机ip,可以使用ipconfig命令查看;端口号是之前设定的8080端口。代码如下:

#include <iostream>
#include<Windows.h>
using namespace std;

int main(int argc,char* argv[])
{
	//初始化动态链接库
	WSADATA ws;
	WSAStartup(MAKEWORD(2, 2), &ws);//22是版本号,加载动态链接库
	int sock = socket(AF_INET, SOCK_STREAM, 0);//AF_INET指明调用TCP/IP协议,SOCK_STREAM是TCP的协议(相对于UDP来讲)
	cout << sock << endl;//打印句柄id,失败返回负值
	//失败提示
	if (sock == -1)
	{
		cout << "create socket failed!" << endl;
		return -1;
	}

	//测试端口号
	unsigned short port = 8080;
	if (argc > 1)
	{
		port = atoi(argv[1]);
	}

	//创建TCP相关的结构体
	sockaddr_in saddr;
	saddr.sin_family = AF_INET;//使用TCP
	saddr.sin_port = htons(port);//本地字节序转网络字节序
	//X86架构是小端的而网络字节流是大端的,
	//Linux不一定,小型linux使用的也是和网路字节序一样的话转换也只是一个空的宏,
	//这时候会可有可无,但考虑兼容性要求建议加上
	saddr.sin_addr.s_addr = htonl(0);//这里可以指定网卡,0是任意的意思

	if (bind(sock, (sockaddr*)&saddr, sizeof(saddr)) != 0)//绑定端口号到上面创建的socket,并判断是否成功
	{
		cout << "bind port " << port << " failed!" << endl;
		return -2;
	}
	else
	{
		cout<< "bind port " << port << " success!" << endl;
	}

	listen(sock, 10);//监听,接受连接;10是列表大小,套接字接收队列的最大大小 
	//accept每调用一次队列就会减少一个
	int client = accept(sock, 0, 0);//不需要连接信息
	cout << client << endl;
	closesocket(sock);//关闭连接

	return 0;
}

这是测试案例:

telnet 192.168.1.110 8080

返回结果如下:

如果要取得连接者的信息的话,得在accept中传入相应的信息:

#include <iostream>
#include<ws2tcpip.h>
#include<Windows.h>

using namespace std;

int main(int argc, char* argv[])
{
	//初始化动态链接库
	WSADATA ws;
	WSAStartup(MAKEWORD(2, 2), &ws);//22是版本号,加载动态链接库
	int sock = socket(AF_INET, SOCK_STREAM, 0);//AF_INET指明调用TCP/IP协议,SOCK_STREAM是TCP的协议(相对于UDP来讲)
	cout << sock << endl;//打印句柄id,失败返回负值
	//失败提示
	if (sock == -1)
	{
		cout << "create socket failed!" << endl;
		return -1;
	}

	//测试端口号
	unsigned short port = 8080;
	if (argc > 1)
	{
		port = atoi(argv[1]);
	}

	//创建TCP相关的结构体
	sockaddr_in saddr;
	saddr.sin_family = AF_INET;//使用TCP
	saddr.sin_port = htons(port);//本地字节序转网络字节序
	//X86架构是小端的而网络字节流是大端的,
	//Linux不一定,小型linux使用的也是和网路字节序一样的话转换也只是一个空的宏,
	//这时候会可有可无,但考虑兼容性要求建议加上
	saddr.sin_addr.s_addr = htonl(0);//这里可以指定网卡,0是任意的意思

	if (bind(sock, (sockaddr*)&saddr, sizeof(saddr)) != 0)//绑定端口号到上面创建的socket,并判断是否成功
	{
		cout << "bind port " << port << " failed!" << endl;
		return -2;
	}
	else
	{
		cout << "bind port " << port << " success!" << endl;
	}

	listen(sock, 10);//监听,接受连接;10是列表大小,套接字接收队列的最大大小 
	//accept每调用一次队列就会减少一个

	sockaddr_in caddr;
	socklen_t len = sizeof(caddr);
	int client = accept(sock, (sockaddr*)&caddr, &len);//取信息
	cout << client << endl;
	char* ip = inet_ntoa(caddr.sin_addr);
	unsigned short cport = ntohs(caddr.sin_port);//网络字节序转本地字节序
	cout << "client ip is " << ip << " port is " << cport << endl;
	closesocket(sock);//关闭连接

	return 0;
}

END

发布了162 篇原创文章 · 获赞 38 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/qq_41938259/article/details/104900319
今日推荐