Socket介绍:
socket即套接字,端口号拼接到IP地址就构成了套接字。如果IP地址是169.254.24,而端口号是3000,那么得到套接字就是(169.254.24:3000),即(主机IP地址:端口号)。
三种不同类型的套接字:
1、 (SOCK-STREAM)流式套接字:提供一种可靠的、面向连接的双向数据传输服务,实现了数据无差错、无重复的发送。发送大批量的数据或者对数据传输有较高的要求时,可以使用流式套接字。
2、 (SOCK-DGRAM)数据报套接字: 提供一种无连接、不可靠的双向数据传输服务。数据包以独立的形式被发送,数据在传输过程中可能会丢失或重复,并且不能保证在接收端按发送顺序接收数据。出现差错的可能性较小或允许部分传输出错的应用场合,可以使用数据报套接字。
3、(SOCK-RAW)原始套接字:该套接字允许对较低层协议(如IP或ICMP)进行直接访问,常用于网络协议分析,检验新的网络协议实现,也可用于测试新配置或安装的网络设备。
客户端/服务端模式:
网络架构使用客户端(Client)-服务器(Server)模式(简称C/S),即客户端向服务器发出请求,服务器接收请求后,提供相应的服务。
服务端:建立socket,声明自身的端口号和地址并绑定到socket,使用listen打开监听,然后不断用accept去查看是否有连接,如果有,捕获socket,并通过recv获取消息的内容,通信完成后调用closeSocket关闭这个对应accept到的socket,如果不再需要等待任何客户端连接,那么用closeSocket关闭掉自身的socket。
客户端:建立socket,通过端口号和地址确定目标服务器,使用Connect连接到服务器,send发送消息,等待处理,通信完成后调用closeSocket关闭socket。
TCP编程步骤:
一、服务端
1、加载套接字库,创建套接字(WSAStartup()/socket());
2、绑定套接字到一个IP地址和一个端口上(bind());
3、将套接字设置为监听模式等待连接请求(listen());
4、请求到来后,接受连接请求,返回一个新的对应于此次连接的套接字(accept());
5、用返回的套接字和客户端进行通信(send()/recv());
6、返回,等待另一个连接请求;
7、关闭套接字,关闭加载的套接字库(closesocket()/WSACleanup());
二、客户端
1、加载套接字库,创建套接字(WSAStartup()/socket());
2、向服务器发出连接请求(connect());
3、和服务器进行通信(send()/recv());
4、关闭套接字,关闭加载的套接字库(closesocket()/WSACleanup());
TCP服务端代码
#include "pch.h"
#include <iostream>
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")
using namespace std;
int main(int argc, char* argv[])
{
//初始化WSA
WORD sockVersion = MAKEWORD(2, 2);
WSADATA wsaData;
if (WSAStartup(sockVersion, &wsaData) != 0)
{
return 0;
}
//创建套接字
SOCKET slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (slisten == INVALID_SOCKET)
{
cout << "create socket error !" << endl;
return 0;
}
//绑定IP和端口
sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(8888);
sin.sin_addr.S_un.S_addr = INADDR_ANY;
if (bind(slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR)
{
cout << "bind error !" << endl;
}
//开始监听
if (listen(slisten, 5) == SOCKET_ERROR)
{
cout << "listen error !" << endl;
return 0;
}
//循环接收数据
SOCKET sClient;
sockaddr_in remoteAddr;
int nAddrlen = sizeof(remoteAddr);
char revData[255];
while (true)
{
cout << "阻塞。。。。等待连接。。。" << endl;
sClient = accept(slisten, (SOCKADDR *)&remoteAddr, &nAddrlen);
if (sClient == INVALID_SOCKET)
{
cout << "accept error !" << endl;
continue;
}
cout << "接受到一个连接:" << inet_ntoa(remoteAddr.sin_addr) << endl;
//接收数据
int ret = recv(sClient, revData, 255, 0);
if (ret > 0)
{
revData[ret] = 0x00;
printf(revData);
}
//发送数据
const char * sendData = "你好,TCP客户端!\n";
send(sClient, sendData, strlen(sendData), 0);
closesocket(sClient);
}
closesocket(slisten);
WSACleanup();
return 0;
}
TCP客户端代码
#include "stdafx.h"
#include<winsock2.h>
#include<iostream>
#include<string>
using namespace std;
#pragma comment(lib, "ws2_32.lib")
int main()
{
WORD sockVersion = MAKEWORD(2, 2);
WSADATA data;
if (WSAStartup(sockVersion, &data) != 0)
{
return 0;
}
while (true)
{
SOCKET sclient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sclient == INVALID_SOCKET)
{
cout << "invalid socket!" << endl;
return 0;
}
sockaddr_in serAddr;
serAddr.sin_family = AF_INET;
serAddr.sin_port = htons(8888);
serAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
if (connect(sclient, (sockaddr *)&serAddr, sizeof(serAddr)) == SOCKET_ERROR)
{
//连接失败
cout << "connect error !" << endl;
closesocket(sclient);
return 0;
}
string data;
cin >> data;
const char * sendData;
sendData = data.c_str(); //string转const char*
/*
send()用来将数据由指定的socket传给对方主机
int send(int s, const void * msg, int len, unsigned int flags)
s为已建立好连接的socket,msg指向数据内容,len则为数据长度,参数flags一般设0
成功则返回实际传送出去的字符数,失败返回-1,错误原因存于error
*/
send(sclient, sendData, strlen(sendData), 0);
char recData[255];
int ret = recv(sclient, recData, 255, 0);
if (ret>0)
{
recData[ret] = 0x00;
cout << recData << endl;
}
closesocket(sclient);
}
WSACleanup();
system("pause");
return 0;
}
网友评论