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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章