服务端:socket->bind->listen->accept->recv/send->close
客户端:socket-connect->send/recv->close
Socket 函数
{
socket()
bind() //服务端使用
listen() //服务端使用
accept() //服务端使用
connect() //客户端使用
send()
recv()
select()
closeSocket()
}
ip地址转换
{
低分ip地址(192.168.123.12/主要是为了好记忆,计算机不认识) 需转换成一个 32位无符号长整数(这个才是真的ip地址);
转换函数:
s_addr = inet_addr(“192.168.123.1”);
}
字节转化
{
@大端字节(big-endian)
@小段字节(little-endian)
@主机字节(host-byte)
{
不同的主机(windows(小端)/linux)用的主机字节不同,要么是大端 要么是小端
}
*网络字节(network-byte)*
{
网络上传输的数据是按大端字节顺序传输的,那么在windows上编程的话那么就需要转换字节序了
}
@转换函数{
htons(主机(host)转换(to)成网络(net)的短整型(short));
htonl(主机(host)转换(to)成网络(net)的长整型(long));
ntohs(); //网络转本机short类型
ntohl(); //网络转本机long类型
}
}
TCP Socket编程
{
@流式套接字
tcp/ip
SOCK_STREAM
@服务端程序:socket->bind->listen->accept->recv/send->close
@客户端:socket-connect->send/recv->close
##TCPServer实现
@头文件
#pragma comment(lib,“ws2_32.lib”);
#include <WinSock2.h>
}
代码:
服务端
#include<iostream>
#include<stdlib.h>
#include<WinSock2.h>
using namespace std;
#pragma comment(lib,"ws2_32.lib")
#pragma warning(disable : 4996)
int main()
{
WSADATA wsaData;
int Ret = 0;
//1.MAKEWORD(2,2): 2.2版本的WinSock;初始化widnows套接字
Ret = WSAStartup(MAKEWORD(2,2), &wsaData);
if (Ret != 0)
{
cout << "WSAStartup init erro:" <<Ret<< endl;
return 0;
}
//2.申请服务端套接字
SOCKET ListingSocket;
ListingSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); //SOCK_STREAM tcp属于流形式的套接字
if (ListingSocket == INVALID_SOCKET)
{
cout << "socket is erro:" << WSAGetLastError() <<endl;
WSACleanup();
return 0;
}
//3.bind
SOCKADDR_IN ServerAddr;
ServerAddr.sin_family = AF_INET; //协议:Internet协议
int port = 5150;
ServerAddr.sin_port = htons(port); //端口(有6w多个端口,但是不能重复,选大一点的端口比较保险);同时要转成(htons)网络使用的字节序
ServerAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); //设置任何客户端的ip都能连接;不限制客户端的ip
if (SOCKET_ERROR == (bind(ListingSocket, (SOCKADDR*)&ServerAddr, sizeof(ServerAddr))))
{
cout << "socket bind erro:" << WSAGetLastError() << endl;
closesocket(ListingSocket); //关闭套接字
WSACleanup();
return 0;
}
//4.开始监听
if (SOCKET_ERROR == (listen(ListingSocket, 5)))//允许5个连接(队列大小是5) 不要设置太大
{
cout << "socket listen erro:" << WSAGetLastError() << endl;
closesocket(ListingSocket); //关闭套接字
WSACleanup();
return 0;
}
cout << "we are wating for connecting on port:" << port << endl;
cout << "Listen(正在监听)" << endl;
//5有客户端连接我们就接受客户端连接
SOCKADDR_IN ClientAddr; //客户端地址
int ClinetAddrLen = sizeof(SOCKADDR); //客户端地址长度
SOCKET NewConnection; //服务端接受成功会得到一个客户端的套接字,每一个新的客户端的套接字代表一个新的连接
NewConnection = accept(ListingSocket,(SOCKADDR*)&ClientAddr, &ClinetAddrLen);
if (NewConnection == INVALID_SOCKET)
{
cout << "socket accept erro:" << WSAGetLastError() << endl;
closesocket(ListingSocket); //关闭套接字
WSACleanup();
return 0;
}
cout << "we successfully got a connection form ip: " << inet_ntoa(ClientAddr.sin_addr) << "; port:" << ntohs(ClientAddr.sin_port) <<endl;
//6.关闭套接字
closesocket(ListingSocket); //关闭套接字,这个例子只接受一个客户端连接
cout << "We are winting for receive data" << endl;
//接受数据
char dataBuffer[1024]; //客户端发来的东西放这里面
if (SOCKET_ERROR == (Ret = recv(NewConnection, dataBuffer, sizeof(dataBuffer), 0)))
{
cout << "socket recv erro:" << WSAGetLastError() << endl;
closesocket(NewConnection); //关闭客户端的套接字
WSACleanup();
return 0;
}
cout << "we successfully recv :"<< Ret << "bytes"<<endl;
//收到的buf都是字符串 我们要把buf 的最后一个字节加上"\0";
dataBuffer[Ret] = '\0';
cout << "recv buf is" << dataBuffer <<endl;
//关闭客户端的套接字做清理
closesocket(NewConnection); //关闭客户端的套接字
WSACleanup();
system("pause");
return 0;
}
客户端
#include<iostream>
#include<stdlib.h>
#include<WinSock2.h>
using namespace std;
#pragma comment(lib,"ws2_32.lib")
#pragma warning(disable : 4996)
int main(int argc, char** argv)
{
if (argc <= 1)
{
//TCPClient 127.0.0.1
cout << "usage : TCPClinet <Server IP address>." << endl;
system("pause");
return 0;
}
WSADATA wsaData;
int Ret = 0;
//1.MAKEWORD(2,2): 2.2版本的WinSock;初始化widnows套接字
Ret = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (Ret != 0)
{
cout << "WSAStartup init erro:" << Ret << endl;
return 0;
}
//2.申请客户端套接字
SOCKET s;
s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //SOCK_STREAM tcp属于流形式的套接字
if (s == INVALID_SOCKET)
{
cout << "socket is erro:" << WSAGetLastError() << endl;
WSACleanup();
return 0;
}
//3.连接服务器
SOCKADDR_IN ServerAddr;
ServerAddr.sin_family = AF_INET; //协议:Internet协议
int port = 5150;
ServerAddr.sin_port = htons(port); //端口(有6w多个端口,但是不能重复,选大一点的端口比较保险);同时要转成(htons)网络使用的字节序
//ServerAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); //设置服务端的地址(这里就在本机测试)
ServerAddr.sin_addr.S_un.S_addr = inet_addr(argv[1]); //设置服务端的地址(使用命令行来输出)
cout << "we are try to connet :" << inet_ntoa(ServerAddr.sin_addr)<<";port:"<<htons(ServerAddr.sin_port)<<endl;
//4. 连接服务端
if (SOCKET_ERROR == (connect(s, (SOCKADDR*)&ServerAddr, sizeof(ServerAddr))))
{
cout << "socket connect erro:" << WSAGetLastError() << endl;
closesocket(s); //关闭套接字
WSACleanup();
return 0;
}
cout << "socket connnetion succeessed, we will send a message to server" << endl;
//5发送数据
if ((Ret = send(s, "fuck?", 5, 0)) == SOCKET_ERROR )
{
cout << "socket send erro:" << WSAGetLastError() << endl;
closesocket(s); //关闭套接字
WSACleanup();
return 0;
}
cout << "we are successed send " << Ret << "bytes to server" << endl;
//6 关闭套接字
closesocket(s); //关闭套接字
WSACleanup();
system("pause");
return 0;
}
验证图: