c++socket双人聊天

一、协议设计

使用流套接字(SOCK_STREAM),流套接字用于面向连接,可靠的数据传输服务。它使用了传输控制协议TCP。在聊天的程序中需要一个服务器一个客户端。
在会话进行的流程中,服务器端先创建套接字(socket())再将其与ip地址和端口绑定(bind()),然后开始监听listen(),再使用accept()阻塞进程直到有客户端连接。客户端创建套接字socket(),再使用connect()建立连接客户端,wirte()请求数据,然后服务器read()接收请求,服务器处理请求之后write()回应数据,客户端用read()接收数据如果数据中没有退出信息,则再回到请求数据的步骤。若有退出指令则客户端退出close()关闭连接然后服务器read()后close()或者服务器先close()关闭连接然后客户端read()后close()。
流程如下图所示:
在这里插入图片描述
在通话开始前,用户端和服务器交换彼此的名字开始通话,由客户端先开始发言,完毕后输入over服务器才能发消息回客户端。之后客户端也是在服务器端输入over才能发言。双方任意一方均可输入“exit“来结束对话退出程序。

二、代码实现

//server.cpp
1.	#include<iostream>  
2.	#include<winsock.h>  
3.	#include<string.h>  
4.	#pragma comment(lib, "ws2_32.lib")   
5.	//加载ws2_32.lib库  
6.	using namespace std;  
7.	int main() {  
8.	  
9.	    WSADATA wsaData; //存放被WSAStartup函数调用后返回的Windows Sockets数据的数据结构  
10.	    WSAStartup(MAKEWORD(2, 2), &wsaData);//声明使用socket2.2版本  
11.	    //创建套接字  
12.	    SOCKET ServerSocket;  
13.	    //地址类型为AD_INET,服务类型为流式(SOCK_STREAM),协议采用TCP  
14.	    ServerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);  
15.	    if (ServerSocket == INVALID_SOCKET)  
16.	    {  
17.	        cout << "套接字创建失败";  
18.	        WSACleanup();  
19.	        return 0;  
20.	    }  
21.	  
22.	    SOCKADDR_IN ServerAddr;  
23.	    ServerAddr.sin_family = AF_INET;     //指定IP格式  
24.	    USHORT uPort = 8888;                 //服务器监听端口  
25.	    ServerAddr.sin_port = htons(uPort);   //绑定端口号  
26.	    ServerAddr.sin_addr.S_un.S_addr = INADDR_ANY;  
27.	    if (bind(ServerSocket, (SOCKADDR*)&ServerAddr, sizeof(ServerAddr)) == SOCKET_ERROR)  //建立捆绑  
28.	    {  
29.	        cout << "绑定失败";  
30.	        closesocket(ServerSocket);  
31.	        return 0;  
32.	    }  
33.	    char server_name[32] = { 0 };  
34.	    cout << "请输入你的名字:";  
35.	    cin.getline(server_name,32);  
36.	  
37.	    /*开始监听*/  
38.	    listen(ServerSocket, 1);  
39.	  
40.	    /*等待连接*/  
41.	    char client_name[32] = { 0 };  
42.	    SOCKET ClientSocket;  
43.	    SOCKADDR_IN ClientAddr;  
44.	    int ClientAddrlen = sizeof(ClientAddr);  
45.	    ClientSocket = accept(ServerSocket,(SOCKADDR*)&ClientAddr,&ClientAddrlen);  
46.	    cout << "等待连接...\n";  
47.	    if (ClientSocket == INVALID_SOCKET)  
48.	    {  
49.	        cout << "客户端发出请求,服务器接收请求失败:\n" << WSAGetLastError();  
50.	        closesocket(ServerSocket);  
51.	        WSACleanup();  
52.	        return 0;  
53.	    }  
54.	    else  
55.	    {  
56.	        cout << "客服端与服务器建立连接成功:\n" ;  
57.	    }  
58.	    char buffer[1024] = { 0 };  
59.	    int relen = 0;  
60.	    int selen = 0;  
61.	    /*通过建立的连接进行通信*/  
62.	    //发送和接受客户端与服务端的名字  
63.	    selen=send(ClientSocket, server_name, strlen(server_name), 0);  
64.	    relen=recv(ClientSocket, client_name, sizeof(client_name), 0);  
65.	    client_name[relen] = '\0';  
66.	    while (1)  
67.	    {  
68.	        while (1)  
69.	        {  
70.	            memset(buffer, 0, sizeof(buffer));//在每次交互前,把之前的buf数据清空,避免缓冲区冗余  
71.	            relen = recv(ClientSocket, buffer, sizeof(buffer), 0);  
72.	            /*buffer[relen] = '\0';*/  
73.	            //接受消息  
74.	            if (strcmp(buffer, "exit") == 0)//输入消息含有exit便退出  
75.	            {  
76.	                cout << "程序将在3秒后退出" << endl;  
77.	                Sleep(3000);  
78.	                closesocket(ServerSocket);  
79.	                closesocket(ClientSocket);  
80.	                WSACleanup();  
81.	                return 0;  
82.	            }  
83.	            else if (strcmp(buffer, "over") == 0)  
84.	            {  
85.	                break;  
86.	            }  
87.	            cout << client_name << ": ";  
88.	            cout << buffer << endl;  
89.	        }  
90.	        while (1) {  
91.	            memset(buffer, 0, sizeof(buffer));  
92.	            cout << server_name << ": ";  
93.	            cin.getline(buffer,1024);  
94.	            //发出消息  
95.	            if (strcmp(buffer, "over") == 0)  
96.	            {  
97.	                selen = send(ClientSocket, buffer, sizeof(buffer), 0);  
98.	                break;  
99.	            }  
100.	            else if(strcmp(buffer, "exit") == 0)  
101.	            {  
102.	                selen = send(ClientSocket, buffer, sizeof(buffer), 0);  
103.	                cout << "程序将在3秒后退出" << endl;  
104.	                Sleep(3000);  
105.	                closesocket(ServerSocket);  
106.	                closesocket(ClientSocket);  
107.	                WSACleanup();  
108.	                return 0;  
109.	            }  
110.	            selen = send(ClientSocket, buffer, sizeof(buffer), 0);  
111.	        }  
112.	    }  
113.	}  

客户端

\\client.cpp
114.	#include<iostream>  
115.	#include<winsock.h>  
116.	#include<string.h>  
117.	#pragma comment(lib, "ws2_32.lib")   
118.	//加载ws2_32.lib库  
119.	using namespace std;  
120.	int main() {  
121.	  
122.	    WSADATA wsaData; //存放被WSAStartup函数调用后返回的Windows Sockets数据的数据结构  
123.	    WSAStartup(MAKEWORD(2, 2), &wsaData);//声明使用socket2.2版本  
124.	    //创建套接字  
125.	    SOCKET ClientSocket;  
126.	    //地址类型为AD_INET,服务类型为流式(SOCK_STREAM),协议采用TCP  
127.	    ClientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);  
128.	    if (ClientSocket == INVALID_SOCKET)  
129.	    {  
130.	        cout << "套接字创建失败";  
131.	        WSACleanup();  
132.	        return 0;  
133.	    }  
134.	  
135.	    SOCKADDR_IN ServerAddr;  
136.	    ServerAddr.sin_family = AF_INET;     //指定IP格式  
137.	    USHORT uPort = 8888;                 //服务器监听端口  
138.	    ServerAddr.sin_port = htons(uPort);   //绑定端口号  
139.	    ServerAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");  
140.	    char client_name[32] = { 0 };  
141.	    cout << "请输入你的名字:";  
142.	    cin.getline( client_name,32);  
143.	    connect(ClientSocket, (SOCKADDR*)&ServerAddr, sizeof(ServerAddr));  
144.	    cout << "连接成功" << endl;  
145.	  
146.	    /*等待连接*/  
147.	    char server_name[32] = { 0 };  
148.	    char buffer[1024] = { 0 };  
149.	    int relen = 0;  
150.	    int selen = 0;  
151.	    /*通过建立的连接进行通信*/  
152.	    //发送和接受客户端与服务端的名字  
153.	    selen = send(ClientSocket, client_name, strlen(client_name), 0);  
154.	    relen = recv(ClientSocket, server_name, sizeof(server_name), 0);  
155.	    /*server_name[relen] = '\0';*/  
156.	    while (1)  
157.	    {  
158.	        while (1) {  
159.	            cout << client_name << ": ";  
160.	            memset(buffer, 0, sizeof(buffer));  
161.	            cin.getline(buffer,sizeof(buffer));  
162.	            if (strcmp(buffer, "exit") == 0)  
163.	            {  
164.	                selen = send(ClientSocket, buffer, sizeof(buffer), 0);  
165.	                cout << "程序将在3秒后退出" << endl;  
166.	                Sleep(3000);  
167.	                closesocket(ClientSocket);  
168.	                WSACleanup();  
169.	                return 0;  
170.	            }  
171.	            else if (strcmp(buffer, "over") == 0)  
172.	            {  
173.	                selen = send(ClientSocket, buffer, sizeof(buffer), 0);  
174.	                break;  
175.	            }  
176.	            selen = send(ClientSocket, buffer, sizeof(buffer), 0);  
177.	        }  
178.	        while (1) {  
179.	            memset(buffer, 0, sizeof(buffer));//在每次交互前,把之前的buf数据清空,避免缓冲区冗余  
180.	            relen = recv(ClientSocket, buffer, sizeof(buffer), 0);  
181.	            //buffer[relen] = '\0';//接受消息  
182.	            if (strcmp(buffer, "exit") == 0)//输入消息含有exit便退出  
183.	            {  
184.	                cout << buffer <<"程序将在3秒后退出" <<endl;  
185.	                Sleep(3000);  
186.	                closesocket(ClientSocket);  
187.	                WSACleanup();  
188.	                return 0;  
189.	            }  
190.	            else if (strcmp(buffer, "over") == 0)  
191.	            {  
192.	                break;  
193.	            }  
194.	            cout << server_name << ": ";  
195.	            cout << buffer << endl;  
196.	        }  
197.	    }  
198.	}  
199

三、 实验结果

在这里插入图片描述

  • 3
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值