API
函数原型:
- int listen(int sockfd, int backlog);
函数作用:声明sockfd处于监听状态,并且最多允许又backlog个客户端处于连接等待状态,如果接收到更多的连接请求就忽略(这里一般不会设置太大)
函数返回值:
- 监听成功返回0,失败返回-1
函数原型:
- int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
参数说明:
- sockfd:新创建的socket套接字
- addr:这是一个输出型参数,当accept函数返回时,输出客户端的地址和端口号
- addrlen :这是一个输入输出型参数,传入的是调用者提供的缓冲区addr的长度,用来避免缓冲区溢出问题;传出的是客户端地址结构体的实际长度。
函数说明:
- 三次握手完成后,服务器调用这个函数建立连接,如果还没有客户端的连接请求,就阻塞等待直到有客户端连接上来
服务器端代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/wait.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
void Usage(){
printf("Usage: ./server [ip] [port]\n");
}
void ProcessRequest(int client_fd,struct sockaddr_in *client_addr)
{
char buf[1024] = {0};
while(1){
ssize_t read_size = read(client_fd, buf, sizeof(buf));
if(read_size < 0){
perror("read");
continue;
}
if(read_size == 0){
printf("client: %s exit!\n",\
inet_ntoa(client_addr->sin_addr));
close(client_fd);
break;
}
buf[read_size] = '\0';
printf("client %s say: %s\n",\
inet_ntoa(client_addr->sin_addr), buf);
write(client_fd, buf, strlen(buf));
}
}
void CreateWorker(int client_fd, struct sockaddr_in *client_addr)
{
pid_t pid = fork();
if(pid < 0){
perror("fork");
return;
}else if(pid == 0){
if(fork() == 0){
ProcessRequest(client_fd, client_addr);
}
exit(0);
}else{
close(client_fd);
waitpid(pid, NULl, 0);
}
}
int main(int argc, char *argv[])
{
if(argc != 3){
Usage();
return 1;
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s._addr = inet_addr(argc[1]);
addr.sin_port = htons(atoi(argv[2]));
int fd = socket(AF_INET, SOCKSTREAM, 0);
if(fd < 0){
perror("socket");
return 1;
}
int ret = bind(fd, (struct sockaddr*)&addr, sizeof(addr));
if(ret < 0){
perror("bind");
return 1;
}
ret = listen(fd, 10);
if(ret < 0){
perror("listen");
return 1;
}
while(1){
struct sockaddr_in client_addr;
socklen_t len = sizeof(client_addr);
int client_fd = accept(fd,(struct sockaddr*)&client_addr,\
&len);
if(client_fd < 0){
perror("accept");
continue;
}
CreateWorker("client_fd, &client_addr);
}
return 0;
}