经过网络程序设计课程的学习,我们了解了socket网络程序编程,接下来,就要学以致用,完成一个hello/hi的网络聊天程序。
- Socket介绍
Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部。
Socket起源于Unix,而Unix/Linux 基本哲学之一就是“一切皆文件”,都可以用“打开open –> 读写write/read –> 关闭close”模式 来操作。Socket就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭)。
你想给另一台计算机发消息,你知道他的IP地址,他的机器上同时运行着qq、迅雷、word、浏览器等程序,你想给他的qq发消息,那想一下,你现在只能通过ip找到他的机器,但如果让这台机器知道把消息发给qq程序呢?答案就是通过port,一个机器上可以有0-65535个端口,你的程序想从网络上收发数据,就必须绑定一个端口,这样,远程发到这个端口上的数据,就全会转给这个程序啦。
-
Socket通信套路
当通过socket建立起2台机器的连接后,本质上socket只干2件事,一是收数据,一是发数据,没数据时就等着。Socket 建立连接的过程跟我们现实中打电话比较像,打电话必须是打电话方和接电话方共同完成的事情,我们分别看看他们是怎么建立起通话的。
接电话方(Socket服务器端):
打电话方(Socket客户端):
- Socket套接字函数
服务端套接字函数
S.bind():绑定主机,端口号到套接字。
S.listen():开始tcp监听。
S.accept():等待客户端连接到来。
客户端套接字函数
S.connect():主动初始化TCP服务连接。
- 一个简单的hello/hi网络聊天程序
服务器端代码如下:
#include
#include
#pragma comment(lib,"ws2_32.lib")
#define MAX 999
using namespace std;
int main()
{
char send_buf[MAX], recv_buf[MAX];
SOCKET ser_listen, ser_accept;
SOCKADDR_IN listen_ADDR, accept_ADDR;
WSADATA wsa;
//绑定socket库版本
if (WSAStartup(MAKEWORD(2,2),&wsa)<0)
{
cout << "绑定socket库版本失败" << endl;
exit(EXIT_FAILURE);
}
//初始化协议族
listen_ADDR.sin_family = AF_INET;
listen_ADDR.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
listen_ADDR.sin_port = htons(5214);
ser_listen = socket(AF_INET, SOCK_STREAM, 0);
//绑定主机,端口
if (bind(ser_listen, (SOCKADDR*)& listen_ADDR, sizeof(SOCKADDR))<0)
{
cout << "socket绑定失败!" << endl;
WSACleanup();
exit(EXIT_FAILURE);
}
//等待连接,此时ser_listen变为被动套接口
if (listen(ser_listen, SOMAXCONN) < 0)
{
cout << "设置监听失败!" << endl;
WSACleanup();
exit(EXIT_FAILURE);
}
cout << "等待客户端连接!" << endl;
//len必须提前初始化,不然accept错误
int len = sizeof(SOCKADDR);
//此时ser_accept为主动套接口
if ((ser_accept = accept(ser_listen, (SOCKADDR*)& accept_ADDR, &len))<0)
{
cout << "连接失败!" << endl;
WSACleanup();
exit(EXIT_FAILURE);
}
cout << "连接建立,请在客户端输入!" << endl;
//消息的传递
while (1)
{
recv(ser_accept, recv_buf, MAX, 0);
cout << "收到:" << recv_buf << endl << "请输入要发送的信息:" << endl;
cin >> send_buf;
send(ser_accept, send_buf, MAX, 0);
}
//结束关闭套接口
closesocket(ser_listen);
closesocket(ser_accept);
WSACleanup();
}
客户端代码:
#include
#include
#pragma comment(lib,"ws2_32.lib")
#define MAX 999
using namespace std;
int main()
{
char send_buf[MAX], recv_buf[MAX];
SOCKET cli_accept;
SOCKADDR_IN cli_ADDR;
WSADATA wsa;
//绑定套接字库版本
if (WSAStartup(MAKEWORD(2, 2), &wsa) < 0)
{
cout << "绑定socket库版本失败" << endl;
exit(EXIT_FAILURE);
}
//初始化协议族
cli_ADDR.sin_family = AF_INET;
cli_ADDR.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
cli_ADDR.sin_port = htons(5214);
cli_accept = socket(AF_INET, SOCK_STREAM, 0);
//连接到服务端套接口
if (connect(cli_accept, (SOCKADDR*)& cli_ADDR, sizeof(SOCKADDR)) < 0)
{
cout << "服务端连接失败!" << endl;
WSACleanup();
exit(EXIT_FAILURE);
}
else
{
cout << "服务端连接成功!" << endl;
}
//消息传递
while (1)
{
cout << "请输入发送信息:" << endl;
cin >> send_buf;
send(cli_accept, send_buf, MAX, 0);
recv(cli_accept, recv_buf, MAX, 0);
cout << "收到:" << recv_buf << endl;
}
//关闭套接口
closesocket(cli_accept);
WSACleanup();
}
先运行server.exe,再运行client.exe,得到如下运行结果: