1) 服务器端
- 接受连接后,建立先新线程会话,为应答式服务,不主动断开。
- 接受客户端消息后,在客户端消息基础上,再加上“I am server”,返回。
- 输出客户端的IP地址、端口号信息和收到的消息
- 等客户端断开,退出线程。
- 显示客户端发来的消息是,同时显示当前连接的客户端数量
2)客户端
- 建立连接后,通过控制台发送消息
- 收到服务器的应答消息后,显示返回的消息
- 当发送”bye bye”时,退出程序
d.退出程序。
运行截图:
下面是完整代码(c++):
服务器:
#include "iostream"
#include "process.h"
#include "WinSock2.h"
#include <WS2tcpip.h>
#include <cstring>
#define PORT 4221
#pragma comment(lib,"ws2_32.lib")
#pragma warning(disable:4996)
using namespace std;
int flag = 0;
void rs(void* par);
int main(int argc, char** argv) {
SOCKET sock_server, newsock;
struct sockaddr_in addr;
struct sockaddr_in client_addr;
//char msgbuffer[256];
//char msg[] = "I am a server!\n";
unsigned hthread;
/*初始化*/
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
cout << "加载失败!\n";
return 0;
}
/*创建套接字*/
if ((sock_server = socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR) {
cout << "创建套接字失败!错误代码:" << WSAGetLastError() << endl;
WSACleanup();
return 0;
}
/*添加绑定本地地址*/
int addr_len = sizeof(struct sockaddr_in);
memset((void*)&addr, 0, addr_len);
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
//addr.sin_addr.s_addr = inet_addr("192.168.56.1");
addr.sin_addr.s_addr = htonl(INADDR_ANY);
/*给监听套接字绑定地址*/
if (bind(sock_server, (struct sockaddr*)&addr, sizeof(addr)) != 0) {
cout << "地址绑定失败!错误代码:" << WSAGetLastError() << endl;
closesocket(sock_server);
WSACleanup();
return 0;
}
/*将套接字设为监听状态*/
if (listen(sock_server, 0) != 0) {
cout << "listen函数调用失败!错误代码:" << WSAGetLastError() << endl;
closesocket(sock_server);
WSACleanup();
return 0;
}
else
cout << "listen......\n";
/* *************接收连接请求并调用子进程*************************** */
while (1) {
newsock = accept(sock_server, (struct sockaddr*)&client_addr, &addr_len);
if (newsock != INVALID_SOCKET) {
// cout << "端口号:" << ntohs(client_addr.sin_port) << " 客户端IP:" << inet_ntoa(client_addr.sin_addr) << endl;
flag=flag+1;
//int* arg = &count;
hthread = _beginthread(rs, 0, (LPVOID)newsock);
}
else
break;
}
closesocket(newsock);
WSACleanup();
return 0;
}
/* ******************子线程函数******************** */
//通讯
void rs(void* par) {
char buffer[1000];
const char* add= " I am server";
SOCKET sock = (SOCKET)par;
sockaddr_in client_addr;
int addr_len = sizeof(client_addr);
getpeername(sock, (struct sockaddr*)&client_addr, &addr_len);
//cout << "\n客户端连接,端口号:" << ntohs(client_addr.sin_port) << " 客户端IP:" << inet_ntoa(client_addr.sin_addr) << endl;
while (true) {
int size = recv(sock, buffer, sizeof(buffer), 0);
cout << "\n来自客户端 ["<< inet_ntoa(client_addr.sin_addr)<<"] - ["<< ntohs(client_addr.sin_port) << "] 的消息:" << buffer << endl;
cout << "现在服务器连接了 " << flag << " 个客户端!"<<endl;
if (strcmp(buffer, "bye bye") == 0) {
cout << "客户端断开,退出线程!";
flag = flag - 1;
break;
}
strcat(buffer, add); //将add添加到buffer数组后
if (send(sock, buffer, strlen(buffer)+1, 0) <= 0) {
flag = flag - 1;
break;
}
}
closesocket(sock);
return;
}
客户端:
#include "iostream"
#include "WinSock2.h"
#include <WS2tcpip.h>
#include <string>
// #define PORT 4221
#pragma comment(lib,"ws2_32.lib")
#pragma warning(disable:4996)
using namespace std;
int main(int argc, char** argv)
{
/*定义相关变量*/
int sock_client;
struct sockaddr_in server_addr;
int addr_len = sizeof(struct sockaddr_in);
char msgbuffer[1000];
/*初始化*/
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
cout << "加载winsock.dll失败!\n";
return 0;
}
/*创建套接字*/
if ((sock_client = socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR) {
cout << "创建套接字失败!错误代码:" << WSAGetLastError() << endl;
WSACleanup();
return 0;
}
/*输入服务器IP地址并填写服务器地址结构*/
char IP[20];
uint16_t port;
cout << "请输入服务器IP地址:";
cin >> IP;
cout << "请输入端口号:";
cin>>port;
memset((void*)&server_addr, 0, addr_len);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
in_addr a;
inet_pton(AF_INET, IP, &a);
server_addr.sin_addr.s_addr = a.S_un.S_addr;
/*与服务器建立连接*/
if (connect(sock_client, (struct sockaddr*)&server_addr, addr_len) != 0) {
cout << "连接失败!错误代码:" << WSAGetLastError() << endl;
closesocket(sock_client);
WSACleanup();
return 0;
}
getchar(); //上面使用了cin函数,有默认换行操作,会导致下面getline读取时,读取为空(不等输入就读取),可以通过getchar()来解决,(吃掉空格)
int size;
/*从键盘输入一行文字发送给服务器!\n*/
while (true) {
string s;
cout << "从键盘输入发给服务器的信息!\n";
getline(cin,s); //从键盘读入一行带空格的字符串
//getchar();
strncpy(msgbuffer, s.c_str(), 1000 - 1); //将字符串的值赋给字符数组
msgbuffer[1000 - 1] = '\0';
/*发送信息*/
if ((size = send(sock_client, msgbuffer, strlen(msgbuffer) + 1, 0)) < 0) {
cout << "发送信息失败!错误代码:" << WSAGetLastError() << endl;
}
else if (size == 0) {
cout << "对方已关闭连接!\n";
}
else
cout << "信息发送成功!\n";
/*结束判断*/
if (strcmp(msgbuffer, "bye bye") == 0) {
cout << " 主动结束通讯!" << endl;
break;
}
/*接收信息并显示*/
if ((size = recv(sock_client, msgbuffer, sizeof(msgbuffer), 0)) < 0) {
cout << "接收信息失败!错误代码:" << WSAGetLastError() << endl;
closesocket(sock_client);
WSACleanup();
return 0;
}
else if (size == 0) {
cout << "对方已关闭连接!\n";
closesocket(sock_client);
WSACleanup();
return 0;
}
else
cout << "The message from Server:" << msgbuffer << endl;
//getchar();
}
/*结束处理*/
closesocket(sock_client);
WSACleanup();
return 0;
}