经过网络程序设计课程的学习,我们了解了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<iostream> #include<winsock.h> #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<iostream> #include<winsock.h> #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,得到如下运行结果:
原文地址:https://www.cnblogs.com/rings/p/12014187.html