只能接收一个连接请求的TCP服务器 。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <arpa/inet.h>
void sys_err(char *error)
{
perror(error);
exit(1);
}
int main(int argc, char **argv)
{
int lfd;
int ret;
struct sockaddr_in serv_addr;
//创建socket,指定IPv4协议族 TCP协议
lfd = socket(AF_INET, SOCK_STREAM, 0);
if (lfd == -1)
{
sys_err("socket error");
}
//初始化一个地址结构 man 7 ip 查看对应信息
serv_addr.sin_family = AF_INET; //选择协议族为IPv4
serv_addr.sin_port = htons(6666); //绑定端口号
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); //监听本地所有IP地址
//绑定服务器地址结构
ret = bind(lfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
if (ret == -1)
{
sys_err("bind error");
}
//设置监听上限,设定链接上限,注意此处不阻塞,同一时刻允许向服务器发起链接请求的数量
ret = listen(lfd, 128);
if (ret == -1)
{
sys_err("listen error");
}
//等待并接收连接请求
struct sockaddr_in client_addr;
socklen_t len = sizeof(client_addr);
//监听客户端链接, 会阻塞
int cfd = accept(lfd, (struct sockaddr *)&client_addr, &len);
if (cfd == -1)
{
sys_err("accept error");
}
printf("accept successful\n");
char ipbuf[64] = { 0 };
printf("client ip:%s, port:%d\n",
inet_ntop(AF_INET, &client_addr.sin_addr.s_addr, ipbuf, sizeof(ipbuf)),
ntohs(client_addr.sin_port));
while (1)
{
char buf[1024] = { 0 };
int len = read(cfd, buf, sizeof(buf));
if (len == -1)
{
sys_err("read error");
}
else if (len == 0)
{
printf("客户端断开连接\n");
close(cfd);
break;
}
else
{
printf("recv buf:%s\n",buf);
for(int i=0; i<len; i++)
{
buf[i] = toupper(buf[i]);
}
printf("send buf: %s", buf);
write(cfd, buf, len);
}
}
close(lfd);
return 0;
}
简单的客户端实现
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include <fcntl.h>
void sys_err(char *error)
{
perror(error);
exit(1);
}
int main(int argc, char **argv)
{
int fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd == -1)
{
sys_err("socket error");
}
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(6666);
inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr.s_addr);
//与服务器建立连接
int ret = connect(fd, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (ret == -1)
{
sys_err("connect error");
}
while (1)
{
char buf[512];
fgets(buf, sizeof(buf), stdin);
//将输入的数据发给服务器
write(fd, buf, strlen(buf));
//接收服务器发过来的数据
int len = read(fd, buf, sizeof(buf));
if (len == 0)
{
sys_err("read error");
}
else if (len == 0)
{
printf("服务器端关闭了连接\n");
break;
}
else
{
printf("recv buf: %s\n", buf);
}
}
close(fd);
return 0;
}
多进程服务器实现多个客户端连接
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <ctype.h>
void sys_err(const char *str)
{
perror(str);
exit(-1);
}
//子进程回收
void recycle(int num)
{
int ret;
while ((ret = waitpid(-1, NULL, WNOHANG)) > 0)
{
printf("recycle pid %d\n", ret);
}
}
int main(int argc, char **argv)
{
pid_t pid;
int lfd, cfd;
int ret;
struct sockaddr_in server;
struct sockaddr_in client;
socklen_t client_len;
lfd = socket(AF_INET, SOCK_STREAM, 0);
if (lfd == -1)
{
sys_err("socket error");
}
//绑定服务器地址信息
server.sin_family = AF_INET;
server.sin_port = htons(6666);
server.sin_addr.s_addr = htonl(INADDR_ANY);
ret = bind(lfd, (struct sockaddr *)&server, sizeof(server));
if (ret == -1)
{
sys_err("bind error");
}
ret = listen(lfd, 128);
if (ret == -1)
{
sys_err("listen error");
}
//注册子进程回收处理
struct sigaction act;
act.sa_flags = 0;
act.sa_handler = recycle;
sigemptyset(&act.sa_mask);
sigaction(SIGCHLD, &act, NULL);
//开始循环接收客户端的连接请求
while (1)
{
int readlen;
char bufip[64] = { 0 };
char buf[1024] = { 0 };
client_len = sizeof(client);
// 父进程接收连接请求
// accept阻塞的时候被信号中断, 处理信号对应的操作之后
// 回来之后不阻塞了, 直接返回-1, 这时候 errno==EINTR
cfd = accept(lfd, (struct sockaddr *)&client, &client_len);
while ( cfd == -1 && errno == EINTR)
{
cfd = accept(lfd, (struct sockaddr *)&client, &client_len);
}
printf("connect sucessful\n");
pid = fork();
if (pid < 0)
{
sys_err("fork error");
}
else if (pid == 0)
{
//关闭用于监听的fd
close(lfd);
//子进程
printf("client ip:%s, port %d\n",
inet_ntop(AF_INET, &client.sin_addr.s_addr, bufip, sizeof(bufip)),
ntohs(client.sin_port));
while (1)
{
readlen = read(cfd, buf, sizeof(buf));
if (readlen == -1)
{
sys_err("read error");
}
else if (readlen == 0)
{
printf("客户端断开连接\n");
close(cfd);
break;
}
else
{
//正常读取
printf("recv from %s, buf: %s\b", bufip, buf);
write(cfd, buf, readlen);
}
}
return 1;
}
else
{
//父进程
//关闭用于通信的fd
close(cfd);
}
}
close(lfd);
return 0;
}
多线程服务器实现多个客户端连接
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <errno.h>
extern errno;
typedef struct sockinfo
{
int fd;
pthread_t tid;
struct sockaddr_in addr;
} sockinfo;
void sys_err(const char *str)
{
perror(str);
exit(1);
}
void *worker(void *arg)
{
char bufip[64];
char buf[1024];
sockinfo *sock = (sockinfo *)arg;
printf("pthread id %lu, client ip: %s, port: %d\n",
sock->tid,
inet_ntop(AF_INET, &sock->addr.sin_addr.s_addr, bufip, sizeof(bufip)),
ntohs(sock->addr.sin_port));
while (1)
{
int len = read(sock->fd, buf, sizeof(buf));
if (len == -1)
{
printf("read error %s\n", strerror(errno));
pthread_exit(NULL);
}
else if (len == 0)
{
printf("有客户端断开连接了\n");
close(sock->fd);
break;
}
else
{
printf("recv from ip %s, buf %s\n", bufip, buf);
write(sock->fd, buf, len);
}
}
return NULL;
}
int main(int argc, char **argv)
{
int lfd;
int ret;
sockinfo sock[256];
int index = 0;
socklen_t client_len;
lfd = socket(AF_INET, SOCK_STREAM, 0);
if (lfd == -1)
{
sys_err("socket error");
}
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(6666);
server.sin_addr.s_addr = htonl(INADDR_ANY);
ret = bind(lfd, (struct sockaddr *)&server, sizeof(server));
if (ret == -1)
{
sys_err("bind error");
}
ret = listen(lfd, 128);
if (ret == -1)
{
sys_err("listen error");
}
// cfd = -1
for (index=0; index < sizeof(sock)/sizeof(sock[0]); index++)
{
sock[index].fd = -1;
}
//等待接收连接请求
while (1)
{
for (index=0; index < sizeof(sock)/sizeof(sock[0]); index++)
{
if (sock[index].fd == -1 )
{
break;
}
}
if (index == 256)
{
break;
}
client_len = sizeof(struct sockaddr_in);
sock[index].fd = accept(lfd, (struct sockaddr *)&sock[index].addr, &client_len);
if (sock[index].fd == -1)
{
sys_err("accept error");
}
ret = pthread_create(&sock[index].tid, NULL, worker, &sock[index]);
if (ret != 0)
{
sys_err("pthread create error");
}
pthread_detach(sock[index].tid);
}
close(lfd);
pthread_exit(NULL);
}
使用select
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
void sys_err(const char *str)
{
perror(str);
exit(1);
}
int main(int argc, char **argv)
{
struct sockaddr_in server;
int lfd;
int ret;
//创建socket
lfd = socket(AF_INET, SOCK_STREAM, 0);
if (lfd == -1)
{
sys_err("socket error");
}
//bind
server.sin_family = AF_INET;
server.sin_port = htons(6666);
server.sin_addr.s_addr = htonl(INADDR_ANY);
ret = bind(lfd, (struct sockaddr *)&server, sizeof(server));
if (ret == -1)
{
sys_err("bind error");
}
//设置监听上限
ret = listen(lfd, 128);
if (ret == -1)
{
sys_err("listen error");
}
//等待接收连接请求
struct sockaddr_in client;
socklen_t client_len = sizeof(client);
int maxfd = lfd;
fd_set reads, temp;
//初始化fd集
FD_ZERO(&reads);
FD_SET(lfd, &reads);
while (1)
{
temp = reads;
ret = select(maxfd+1, &temp, NULL, NULL, NULL);
if (ret == -1)
{
sys_err("select error");
}
if (FD_ISSET(lfd, &temp))
{
//接受连接请求,不阻塞
int cfd = accept(lfd, (struct sockaddr *)&client, &client_len);
if (cfd == -1)
{
sys_err("accept error");
}
char ip[64];
printf("new client IP:%s, port:%d\n",
inet_ntop(AF_INET, &client.sin_addr.s_addr, ip, sizeof(ip)),
ntohs(client.sin_port));
//将新的fd添加到集合中
FD_SET(cfd, &reads);
//更新最大fd
maxfd = maxfd < cfd ? cfd : maxfd;
}
//数据读写
for (int i=lfd+1; i<=maxfd; i++)
{
if (FD_ISSET(i, &temp))
{
char buf[1024] = { 0 };
int len = recv(i, buf, sizeof(buf), 0);
if (len == -1)
{
perror("recv error");
}
else if (len == 0)
{
printf("client 断开连接\n");
close(i);
//从集合中删除i
FD_CLR(i, &reads);
}
else
{
printf("recv buf: %s\n", buf);
send(i, buf, strlen(buf)+1, 0);
}
}
}
}
close(lfd);
return 0;
}
使用poll
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include <poll.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
int main(int argc, char **argv)
{
int lfd;
struct sockaddr_in server, client;
socklen_t client_len;
int ret;
lfd = socket(AF_INET, SOCK_STREAM, 0);
if (lfd == -1)
{
perror("socket error");
exit(1);
}
server.sin_family = AF_INET;
server.sin_port = htons(6666);
server.sin_addr.s_addr = htonl(INADDR_ANY);
ret = bind(lfd, (struct sockaddr *)&server, sizeof(server));
if (ret == -1)
{
perror("bind error");
exit(1);
}
ret = listen(lfd, 128);
if (ret == -1)
{
perror("listen error");
exit(1);
}
//poll结构体
struct pollfd allfd[1024];
int max_index = 0;
for (int i=0; i<1024; i++)
{
allfd[i].fd = -1;
allfd[i].events = POLLIN;
}
allfd[0].fd = lfd;
allfd[0].events = POLLIN;
while (1)
{
int i=0;
ret = poll(allfd, max_index+1, -1);
if (ret == -1)
{
perror("poll error");
exit(1);
}
if (allfd[0].revents & POLLIN)
{
char ip[64];
client_len = sizeof(client);
int cfd = accept(lfd, (struct sockaddr*)&client, &client_len);
if (cfd == -1)
{
perror("accept error");
exit(1);
}
printf("client ip:%s, port:%d\n",
inet_ntop(AF_INET, &client.sin_addr.s_addr, ip, sizeof(ip)),
ntohs(client.sin_port));
for (i=0; i<1024; i++)
{
if (allfd[i].fd == -1)
{
allfd[i].fd = cfd;
break;
}
}
//last
max_index = max_index < i? i: max_index;
}
//foreach
for (i=1; i<=max_index; i++)
{
int fd = allfd[i].fd;
if (fd == -1)
{
continue;
}
if (allfd[i].revents & POLLIN)
{
char buf[1024] = {0};
int len = recv(fd, buf, sizeof(buf), 0);
if (len == -1)
{
perror("recv error");
exit(1);
}
else if (len == 0)
{
printf("客户已经断开连接\n");
allfd[i].fd = -1;
close(fd);
}
else
{
printf("recv buf = %s\n",buf);
for (int j=0; j<len; j++)
{
buf[j] = toupper(buf[j]);
}
send(fd, buf, strlen(buf)+1, 0);
}
}
}
}
close(lfd);
return 0;
}
epoll 水平触发模式
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/epoll.h>
#include <arpa/inet.h>
#include <ctype.h>
int main(int argc, char **argv)
{
int lfd;
int ret;
struct sockaddr_in server, client;
socklen_t client_len;
lfd = socket(AF_INET, SOCK_STREAM, 0);
if (lfd == -1)
{
perror("socket error");
exit(1);
}
//绑定服务器地址信息
server.sin_family = AF_INET;
server.sin_port = htons(6666);
server.sin_addr.s_addr = htonl(INADDR_ANY);
ret = bind(lfd, (struct sockaddr *)&server, sizeof(server));
if (ret == -1)
{
perror("bind error");
exit(1);
}
//设置监听上限
ret = listen(lfd, 128);
if (ret == -1)
{
perror("listen error");
exit(1);
}
//开始epoll的相关设置
//创建epoll树
int epfd = epoll_create(2000);
struct epoll_event ev;
ev.events = EPOLLIN;
ev.data.fd = lfd;
epoll_ctl(epfd, EPOLL_CTL_ADD, lfd, &ev);
struct epoll_event all[2000];
while (1)
{
//使用epoll通知内核IO检测
ret = epoll_wait(epfd, all, sizeof(all)/sizeof(all[0]), -1);
//遍历数组中的前ret个元素
for (int i=0; i<ret; i++)
{
int fd = all[i].data.fd;
if (fd == lfd)
{
client_len = sizeof(client);
//接受连接请求
int cfd = accept(lfd, (struct sockaddr *)&client, &client_len);
if (cfd == -1)
{
perror("accept error");
exit(1);
}
//将新连接的客户端cfd挂到树上
struct epoll_event temp;
temp.events = EPOLLIN;
temp.data.fd = cfd;
epoll_ctl(epfd, EPOLL_CTL_ADD, cfd, &temp);
//打印ip信息
char ip[64];
printf("new client ip:%s,port%d\n",
inet_ntop(AF_INET, &client.sin_addr.s_addr, ip, sizeof(ip)),
ntohs(client.sin_port));
}
else
{
//客户端数据发送过来
if (!all[i].events & EPOLLIN)
{
continue;
}
char buf[1024] = { 0 };
int len = recv(fd, buf, sizeof(buf), 0);
if (len == -1)
{
perror("recv error");
exit(1);
}
else if (len == 0)
{
printf("客户端断开连接\n");
ret = epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);
if (ret == -1)
{
perror("epoll_ctl error");
exit(1);
}
close(fd);
}
else
{
printf("recv buf:%s\n", buf);
write(fd, buf, len);
}
}
}
}
close(lfd);
return 0;
}