Socket programming
In order for the client and server to communicate over the network, Socket
programming .
The server first calls the socket()
function to create the network protocol as IPv4
and the transmission protocol as TCP
, Socket
and then calls the bind()
function to Socket
bind an IP
address and port to this . Then, the server can call the listen()
function to monitor. After entering the monitoring state, accept()
it can obtain the client's connection from the kernel by calling the function. If there is no client connection, it will block and wait for the arrival of the client connection.
Socket
After the client is created , it calls connect()
the function to initiate a connection. The parameters of the function should specify the IP
address and port number of the server, and then start the three-way handshake .
During the TCP
connection process, the server's kernel actually Socket
maintains two queues for each :
- semi-join queue
- fully connected queue
When TCP
the fully connected queue is not empty, the server-side accept()
function will take out a completed connection from the TCP
fully Socket
return to the application, which will be used for subsequent data transmission Socket
. Therefore, the three-way handshake Socket
and the transmission of data Socket
are not the same.
After the connection is established, the client and the server begin to transmit data to each other, and both parties read()
can read and write()
write data through the and functions.
Let's take a look at the communication implemented in the way of synchronous blocking . Socket
Put two cpp files in different projects and generate them separately.
server.cpp
#include <stdio.h>
#include <windows.h>
#pragma comment(lib, "ws2_32.lib")
int main()
{
//1. 请求协议版本
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
printf("request failed!\n");
return -1;
}
printf("request protocol success!\n");
//2. 创建Socket
SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (serverSocket == SOCKET_ERROR) {
printf("create failed!\n");
WSACleanup();
return -2;
}
printf("create socket success!\n");
//3.创建协议族
SOCKADDR_IN addr = {
0 };
addr.sin_family = AF_INET; //协议版本
addr.sin_addr.S_un.S_addr = inet_addr("192.168.1.127");
addr.sin_port = htons(10086);//0-65535 10000左右
//4.绑定
int r = bind(serverSocket, (sockaddr*)&addr, sizeof addr);
if (-1 == r) {
printf("bind failed!\n");
closesocket(serverSocket);
WSACleanup();
return -2;
}
printf("bind success!\n");
//5.监听
r = listen(serverSocket, 10);
if (-1 == r) {
printf("listen failed!\n");
closesocket(serverSocket);
WSACleanup();
return -2;
}
printf("listen success!\n");
//6.等待客户端连接 阻塞
SOCKADDR_IN cAddr = {
0 };
int len = sizeof(cAddr);
SOCKET clientSocket = accept(serverSocket, (sockaddr*)&cAddr, &len);
if (SOCKET_ERROR == clientSocket) {
printf("serverd failed!\n");
closesocket(clientSocket);
WSACleanup();
return -2;
}
printf("one client(%s) has connected server!\n", inet_ntoa(cAddr.sin_addr));
//7.通信
char buff[1024];
while (1) {
r = recv(clientSocket, buff, 1023, NULL);
if (r > 0) {
buff[r] = 0; // 添加'\0'
printf(">>%s\n", buff);
}
}
return 0;
}
client.cpp
#include <stdio.h>
#include <windows.h>
#pragma comment(lib, "ws2_32.lib")
int main()
{
//1. 请求协议版本
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
printf("request failed!\n");
return -1;
}
printf("request protocol success!\n");
//2. 创建Socket
SOCKET clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (clientSocket == SOCKET_ERROR) {
printf("create failed!\n");
WSACleanup();
return -2;
}
printf("create socket success!\n");
//3.获取服务器协议族
SOCKADDR_IN addr = {
0 };
addr.sin_family = AF_INET; //协议版本
addr.sin_addr.S_un.S_addr = inet_addr("192.168.1.127");
addr.sin_port = htons(10086);//0-65535 10000左右
//4.连接服务器
int r = connect(clientSocket, (sockaddr*)&addr, sizeof addr);
if (r == -1) {
printf("connecting server failed!\n");
return -1;
}
printf("connecting server success!\n");
//5.通信
char buff[1024];
while (1) {
memset(buff, 0, 1024);
printf("please enter your words: ");
gets_s(buff);
r = send(clientSocket, buff, strlen(buff), NULL);
}
return 0;
}
Communication effect
multithreading model
The synchronous blocking method can only allow the server to serve one client. When the server does not end the network I/O
of the current client, other clients cannot connect to the server. Therefore, we can use a multi-threading model to handle requests from multiple clients.
server.cpp
#include <stdio.h>
#include <windows.h>
#pragma comment(lib, "ws2_32.lib")
SOCKADDR_IN cAddr = {
0 };
int len = sizeof(cAddr);
SOCKET clientSocket[1024];
int count = 0;
void communication(int idx) {
char buff[1024];
int r;
while (1) {
r = recv(clientSocket[idx], buff, 1023, NULL);
if (r > 0) {
buff[r] = 0;
printf("%d:%s\n", idx, buff);
//广播数据
for (int i = 0; i < count; i++) {
send(clientSocket[i], buff, strlen(buff), NULL);
}
}
}
}
int main()
{
//1. 请求协议版本
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
printf("request failed!\n");
return -1;
}
printf("request protocol success!\n");
//2. 创建Socket
SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (serverSocket == SOCKET_ERROR) {
printf("create failed!\n");
WSACleanup();
return -2;
}
printf("create socket success!\n");
//3.创建协议族
SOCKADDR_IN addr = {
0 };
addr.sin_family = AF_INET; //协议版本
addr.sin_addr.S_un.S_addr = inet_addr("192.168.1.127");
addr.sin_port = htons(10086);//0-65535 10000左右
//4.绑定
int r = bind(serverSocket, (sockaddr*)&addr, sizeof addr);
if (-1 == r) {
printf("bind failed!\n");
closesocket(serverSocket);
WSACleanup();
return -2;
}
printf("bind success!\n");
//5.监听
r = listen(serverSocket, 10);
if (-1 == r) {
printf("listen failed!\n");
closesocket(serverSocket);
WSACleanup();
return -2;
}
printf("listen success!\n");
//6.等待客户端连接 阻塞
while (1) {
clientSocket[count] = accept(serverSocket, (sockaddr*)&cAddr, &len);
if (SOCKET_ERROR == clientSocket[count]) {
printf("serverd failed!\n");
closesocket(serverSocket);
WSACleanup();
return -2;
}
printf("one client(%s) has connected server!\n", inet_ntoa(cAddr.sin_addr));
CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)communication, (char*)count, NULL, NULL);
count++;
}
//7.通信
char buff[1024];
while (1) {
r = recv(clientSocket[count], buff, 1023, NULL);
if (r > 0) {
buff[r] = 0; // 添加'\0'
printf(">>%s\n", buff);
}
}
return 0;
}
client.cpp
#include <stdio.h>
#include <graphics.h> //easyX
#pragma comment(lib, "ws2_32.lib")
SOCKET clientSocket;
HWND hWnd;
int count = 0;
void received() {
char recvBuff[1024];
int r;
while (1) {
r = recv(clientSocket, recvBuff, 1023, NULL);
if (r > 0) {
recvBuff[r] = 0;
outtextxy(0, count * 20, recvBuff);
count++;
}
}
}
int main()
{
initgraph(300, 400, SHOWCONSOLE);
//1. 请求协议版本
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
printf("request failed!\n");
return -1;
}
printf("request protocol success!\n");
//2. 创建Socket
clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (clientSocket == SOCKET_ERROR) {
printf("create failed!\n");
WSACleanup();
return -2;
}
printf("create socket success!\n");
//3.获取服务器协议族
SOCKADDR_IN addr = {
0 };
addr.sin_family = AF_INET; //协议版本
addr.sin_addr.S_un.S_addr = inet_addr("192.168.1.127");
addr.sin_port = htons(10086);//0-65535 10000左右
//4.连接服务器
int r = connect(clientSocket, (sockaddr*)&addr, sizeof addr);
if (r == -1) {
printf("connecting server failed!\n");
return -1;
}
printf("connecting server success!\n");
//5.通信
char buff[1024];
CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)received, NULL, NULL, NULL);
while (1) {
memset(buff, 0, 1024);
printf("please enter your words: ");
gets_s(buff);
r = send(clientSocket, buff, strlen(buff), NULL);
}
return 0;
}
references