当前位置:网站首页>C language simple TCP server program
C language simple TCP server program
2022-07-22 18:37:00 【qq_ forty-two million one hundred and twenty thousand eight hun】
C Language TCP Server program
List of articles
Project introduction
Simplicity of the project TCP The server program can accept text messages sent by the client , And display it on the terminal
key technology
There are generally two ways to implement a server that accepts concurrent requests :
- One request one thread
- IO Multiplexing ,epoll technology
Code implementation
One request one thread
First , On the server side, you need to create a file descriptor for listening (sockfd), This is equivalent to the doorman of the hotel , After entering the hotel, the customer is served by other waiters , Equivalent to creating a communication file descriptor (clientfd):
int main(int argc, char *argv[])
{
if(argc < 2)
{
printf("Param Error\n");
return -1;
}
int port = atoi(argv[1]);
// Create a listening file descriptor , It is equivalent to the welcoming staff at the door of the hotel
// Providing services to customers is done by other waiters
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in addr;
memset(&addr, 0, sizeof(struct sockaddr_in));// Empty the structure
addr.sin_family = AF_INET;
addr.sin_port = htons(port); // Convert host byte order to network byte order
addr.sin_addr.s_addr = INADDR_ANY;
// Set up port multiplexing , stay bind Previous call
int opt = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
if(bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0)
{
perror("bind");
return -2;
}
// utilize sockfd monitor
// The second parameter specifies the maximum connection request that can be processed
if(listen(sockfd, 5) < 0)
{
perror("listen");
return -3;
}
// Create for actual communication fd
while(1)
{
// This user address structure variable is used to receive data
struct sockaddr_in client_addr;
memset(&client_addr, 0x00, sizeof(struct sockaddr_in));
socklen_t client_len = sizeof(client_addr);
// Create a communication file descriptor by listening to the file descriptor , Blocked by default
// The client information will be stored in client_addr in
int clientfd = accept(sockfd, (struct sockaddr*)&client_addr, &client_len);
// A request , One thread
pthread_t thread_t;
// The first parameter is the output parameter , The following function will write data to this parameter
pthread_create(&thread_t, NULL, client_routine, &clientfd);
}
}
Used to receive data Callback function
void *client_routine(void *arg)
{
int clientfd = *(int *)arg;
while(1)
{
char buffer[BUFFER_LENGTH];
memset(buffer, 0x00, BUFFER_LENGTH);
// Blocking mode recv, Hang up and wait when there is no data to read
// Default socket It's blocked Unblock and unblock recv The return value is indistinguishable , All are <0 error ;=0 Connection is closed ;>0 Received data size ,
int len = recv(clientfd, buffer, BUFFER_LENGTH, 0);
if(len < 0)
{
close(clientfd);
break;
}
else if(len == 0) // disconnect
{
close(clientfd);
break;
}
else
{
printf("Recv: %s, %d byte(s)\n", buffer, len);
}
}
}
epoll To realize the connection of multiple clients TCP Server program
epoll It's a kind of IO Multiplexing technology , It can be simply understood as epoll Help us monitor the file descriptor we specify (socket) Whether it is readable or writable .
keyword :epoll_ctl,epoll_create,epoll_wait
epoll Horizontal trigger and edge trigger
This edge trigger and horizontal trigger are both for testing IO Is there any data coming :
Level trigger (EPOLLLT)
Data always triggers
Edge trigger (EPOLLET)
data From nothing to talent Will trigger
Generally speaking, edge trigger has higher performance in some scenes ( Less triggers ).
The code is as follows :
int main(int argc, char *argv[])
{
if(argc < 2)
{
printf("Param Error\n");
return -1;
}
int port = atoi(argv[1]);
// Create a listening file descriptor , It is equivalent to the welcoming staff at the door of the hotel
// Providing services to customers is done by other waiters
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in addr;
memset(&addr, 0, sizeof(struct sockaddr_in));// Empty the structure
addr.sin_family = AF_INET;
addr.sin_port = htons(port); // Convert host byte order to network byte order
addr.sin_addr.s_addr = INADDR_ANY;
// Set up port multiplexing , stay bind Previous call
int opt = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
if(bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0)
{
perror("bind");
return -2;
}
// utilize sockfd monitor
// The second parameter specifies the maximum connection request that can be processed
if(listen(sockfd, 5) < 0)
{
perror("listen");
return -3;
}
// Use epoll Reuse IO
// Only fill in a parameter greater than 0 It's OK , This parameter used to specify the maximum number of listening events
// from Linux 2.6.8 Start ,max_size Parameters are ignored , But it must be greater than zero ,
// Because now you can dynamically adjust the size of the required data structure
int epfd = epoll_create(1); // 1. Create an administrator to monitor events fd
// An array of events for accepting results
struct epoll_event events[EPOLL_SIZE] = {
0};
struct epoll_event ev;
// Data coming socketfd, It's readable , It triggers EPOLLIN
// Opposite end ( client ) Read some data and go , It means you can go to this socketfd Yes , It triggers EPOLLOUT
ev.events = EPOLLIN;
ev.data.fd = sockfd;
//EPOLL_CTL_ADD: stay epoll Add a file descriptor to the watch list of ( The parameter fd), Specify the event type to monitor ( Parameters event)
epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev);
while(1)
{
// Returns the number of trigger events , The triggered event is stored in events in ,
// The fourth parameter : Indicates the maximum waiting time when no event is detected
// -1 It means blocking when no event comes ,0 Indicates non blocking , No event will come back and skip
int nready = epoll_wait(epfd, events, EPOLL_SIZE, 5);
if(nready == -1) continue;
int i = 0;
for(i = 0;i < nready;++i)
{
// The event that changes is the listening file descriptor
// Indicates that there is a connection coming
if(events[i].data.fd == sockfd)
{
struct sockaddr_in client_addr;
memset(&client_addr, 0x00, sizeof(struct sockaddr_in));
socklen_t client_len = sizeof(client_addr);
// Get the communication file descriptor , And get the address of the client
int clientfd = accept(sockfd, (struct sockaddr*)&client_addr, &client_len);
// Give Way epoll The administrator of monitors this clientfd
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = clientfd;
epoll_ctl(epfd, EPOLL_CTL_ADD, clientfd, &ev);
}
else // The file descriptor corresponding to the triggered event is the communication file descriptor , Then accept the data
{
int clientfd = events[i].data.fd;
char buffer[BUFFER_LENGTH] = {
0};
int len = recv(clientfd, buffer, BUFFER_LENGTH, 0);
if(len < 0)
{
close(clientfd);
// take client Release monitoring of corresponding events
ev.events = EPOLLIN;
ev.data.fd = clientfd;
epoll_ctl(epfd, EPOLL_CTL_DEL, clientfd, &ev);
}
else if(len == 0) // Connection is broken
{
close(clientfd);
ev.events = EPOLLIN;
ev.data.fd = clientfd;
epoll_ctl(epfd, EPOLL_CTL_DEL, clientfd, &ev);
}
else
{
printf("Recv: %s, %d byte(s)\n", buffer, len);
}
}
}
}
return 0;
}
Complete code
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <fcntl.h>
#define BUFFER_LENGTH 1024
#define EPOLL_SIZE 1024
void *client_routine(void *arg)
{
int clientfd = *(int *)arg;
while(1)
{
char buffer[BUFFER_LENGTH];
memset(buffer, 0x00, BUFFER_LENGTH);
// Blocking mode recv, Hang up and wait when there is no data to read
int len = recv(clientfd, buffer, BUFFER_LENGTH, 0);
if(len < 0)
{
close(clientfd);
break;
}
else if(len == 0) // disconnect
{
close(clientfd);
break;
}
else
{
printf("Recv: %s, %d byte(s)\n", buffer, len);
}
}
}
int main(int argc, char *argv[])
{
if(argc < 2)
{
printf("Param Error\n");
return -1;
}
int port = atoi(argv[1]);
// Create a listening file descriptor , It is equivalent to the welcoming staff at the door of the hotel
// Providing services to customers is done by other waiters
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in addr;
memset(&addr, 0, sizeof(struct sockaddr_in));// Empty the structure
addr.sin_family = AF_INET;
addr.sin_port = htons(port); // Convert host byte order to network byte order
addr.sin_addr.s_addr = INADDR_ANY;
// Set up port multiplexing , stay bind Previous call
int opt = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
if(bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0)
{
perror("bind");
return -2;
}
// utilize sockfd monitor
// The second parameter specifies the maximum connection request that can be processed
if(listen(sockfd, 5) < 0)
{
perror("listen");
return -3;
}
#if 0
// Create for actual communication fd
while(1)
{
// This user address structure variable is used to receive data
struct sockaddr_in client_addr;
memset(&client_addr, 0x00, sizeof(struct sockaddr_in));
socklen_t client_len = sizeof(client_addr);
// Create communication file descriptor
int clientfd = accept(sockfd, (struct sockaddr*)&client_addr, &client_len);
// A request , One thread
pthread_t thread_t;
// The first parameter is the output parameter , The following function will write data to this parameter
pthread_create(&thread_t, NULL, client_routine, &clientfd);
}
#else
// Use epoll Reuse IO
// Only fill in a parameter greater than 0 It's OK , This parameter used to specify the maximum number of listening events
// from Linux 2.6.8 Start ,max_size Parameters are ignored , But it must be greater than zero ,
// Because now you can dynamically adjust the size of the required data structure
int epfd = epoll_create(1); // 1. Create an administrator to monitor events fd
// An array of events for accepting results
struct epoll_event events[EPOLL_SIZE] = {
0};
struct epoll_event ev;
// Data coming socketfd, It's readable , It triggers EPOLLIN
// Opposite end ( client ) Read some data and go , It means you can go to this socketfd Yes , It triggers EPOLLOUT
ev.events = EPOLLIN;
ev.data.fd = sockfd;
//EPOLL_CTL_ADD: stay epoll Add a file descriptor to the watch list of ( The parameter fd), Specify the event type to monitor ( Parameters event)
epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev);
while(1)
{
// Returns the number of trigger events , The triggered event is stored in events in ,
// The fourth parameter : Indicates the maximum waiting time when no event is detected
// -1 It means blocking when no event comes ,0 Indicates non blocking , No event will come back and skip
int nready = epoll_wait(epfd, events, EPOLL_SIZE, 5);
if(nready == -1) continue;
int i = 0;
for(i = 0;i < nready;++i)
{
// The event that changes is the listening file descriptor
// Indicates that there is a connection coming
if(events[i].data.fd == sockfd)
{
struct sockaddr_in client_addr;
memset(&client_addr, 0x00, sizeof(struct sockaddr_in));
socklen_t client_len = sizeof(client_addr);
// Get the communication file descriptor , And get the address of the client
int clientfd = accept(sockfd, (struct sockaddr*)&client_addr, &client_len);
// Give Way epoll The administrator of monitors this clientfd
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = clientfd;
epoll_ctl(epfd, EPOLL_CTL_ADD, clientfd, &ev);
}
else // The file descriptor corresponding to the triggered event is the communication file descriptor , Then accept the data
{
int clientfd = events[i].data.fd;
char buffer[BUFFER_LENGTH] = {
0};
int len = recv(clientfd, buffer, BUFFER_LENGTH, 0);
if(len < 0)
{
close(clientfd);
// take client Release monitoring of corresponding events
ev.events = EPOLLIN;
ev.data.fd = clientfd;
epoll_ctl(epfd, EPOLL_CTL_DEL, clientfd, &ev);
}
else if(len == 0) // Connection is broken
{
close(clientfd);
ev.events = EPOLLIN;
ev.data.fd = clientfd;
epoll_ctl(epfd, EPOLL_CTL_DEL, clientfd, &ev);
}
else
{
printf("Recv: %s, %d byte(s)\n", buffer, len);
}
}
}
}
#endif
return 0;
}
Compile and start
Use NetAssist test
The server accepts data
边栏推荐
- 力扣解法汇总241-为运算表达式设计优先级
- 关于scrollTo滚动offsetTop到顶部的距离的bug找了两个小时
- Geowebcache publishes ArcGIS slice data
- DOM简介及查询
- Laravel 解决【1045】Access denied for user ‘homestead‘@‘localhost‘ (usin g password: YES)
- set up ovn based sr-iov test env (by quqi99)
- centos7.5下添加gd库然后mysql拓展库没了mysql拓展的配置也没问题,phpinfo中就是没有mysql拓展
- 为什么chrome视频时卡得厉害(by quqi99)
- SQL设计教学管理库
- Fabric.js 控制元素层级
猜你喜欢
Laravel 解决【1045】Access denied for user ‘homestead‘@‘localhost‘ (usin g password: YES)
ip,子网掩码,网关,IPS与IDS
微信公众号网页授权----redirect_uri域名与后台配置不一致,错误码10003 错误
Fabric. JS centered element
[10:00 public class]: cloud video conference system privatization practice
关于scrollTo滚动offsetTop到顶部的距离的bug找了两个小时
this指向问题
Date对象简介
真的有必要定义VO,BO,PO,DO,DTO吗?
【Audio】基于STM32 I2S移植WM8978 Audio Codec驱动
随机推荐
DOM添加
协议与端口
【Audio】I2S传输PCM音频数据分析总结(二)
php如何防止csrf攻击
力扣解法汇总731-我的日程安排表 II
"Review of software engineering in Wuhan University of technology" Chapter 7 | software testing
数据湖(十八):Flink与Iceberg整合SQL API操作
Try kolla-ansible (by quqi99)
力扣解法汇总729-我的日程安排表 I
力扣解法汇总1108-IP 地址无效化
Js高级-函数的理解
[标准规范] 低代码的概念和定义到底是什么?无代码是否属于低代码?
力扣解法汇总532-数组中的 k-diff 数对
uniapp 微信小程序地图,在高德app、腾讯app、百度app、苹果地图app 中打开
【STM32】STM32 SDIO SD卡读写测试(四)-- SD_Test之Transfer Mode阶段
Rocky basic exercise -shell SCRIPT-1
MySQL修改密码不成功(无效)的解决办法
charm zaza functional test (by quqi99)
juju debug hacks (by quqi99)
Le mot de passe MySQL est correct, mais une erreur de démarrage n'a pas été signalée pour créer des connexions initiales de pool. Accès refusé pour l'utilisateur 'root' @ 'localhost