#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <getopt.h>
#define MGS "hallo nihao"
void print_usage(char *progname)
{
printf("%s usage:\n",progname);
printf("-p(--port):server listen port\n");
printf("-h(--help):print the hellp\n");
}
int main(int argc,char** argv)
{
int sockfd=-1;
int rv=-1;
struct sockaddr_in servaddr;
struct sockaddr_in cliaddr;
int port=0;
socklen_t len;
int ch;
pid_t pid;
int clifd;
struct option opts[]={
{"port",required_argument,NULL,'p'},
{"help",no_argument,NULL,'h'},
{NULL,0,NULL,0}
};
while((ch=getopt_long(argc,argv,"p:h",opts,NULL))!=-1)
{
switch(ch)
{
case 'p':
port=atoi(optarg);
break;
case 'h':
print_usage(argv[0]);
return 0;
}
}
if(!port)
{
print_usage(argv[0]);
}
sockfd =socket(AF_INET ,SOCK_STREAM,0);
if(sockfd<0)
{
printf("socket is failure :%s\n",strerror(errno));
return -1;
}
printf("The socket is seccessfully\n");
memset(&servaddr,0,sizeof(servaddr));
servaddr.sin_family =AF_INET;
servaddr.sin_port = htons(port);
servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
rv=bind(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr));
if(rv<0)
{
printf("Socket[%d] bind ont port [%d]failure:%s\n",sockfd,port,strerror(errno));
return -2;
}
listen(sockfd,13);
printf("listen cliant on port [%d]\n",port);
while(1)
{
clifd=accept(sockfd,(struct sockaddr *)&cliaddr,&len);
if(clifd<0)
{
printf("Accept new client failure:%s\n",strerror(errno));
continue;
}
printf("Accept new client [%s:%d] successfully\n",inet_ntoa(cliaddr.sin_addr),ntohs(cliaddr.sin_port));
pid=fork();
if(pid<0)
{
printf("fork() to child failure:%s\n",strerror(errno));
close(clifd);
continue;
}
if(pid>0)
{
close(clifd);
continue;
}
if(pid==0)
{
char buf[1024];
int i;
printf("this is child,and child process start to commuicate with socket client...\n");
close(sockfd);
while(1)
{
printf("Next message\n");
memset(buf,0,sizeof(buf));
rv=read(clifd,buf,sizeof(buf));
if(rv<0)
{
printf("Read data from client by clifdfd[%d] failure:%s\n",clifd,strerror(errno));
close(clifd);
continue;
}
else if(rv==0)
{
printf("Socket[%d] get disconnected\n",clifd);
close(clifd);
continue;
}
printf("From[%s] data\n",inet_ntoa(cliaddr.sin_addr));
printf("Read %d bytes data from client:%s\n",rv,buf);
rv=write(clifd,MGS,strlen(MGS));
if(rv<0)
{
printf("write to clien by clifd[%d] failure:%s\n",clifd,strerror(errno));
close(clifd);
continue;
}
}
}
}
close(sockfd);
return 0;
}
bind函数:
bind函数把一个本地协议地址赋予一个套接字。对于网际协议,协议地址是32位的IPv4地址或是128位的IPv6地址与16位的TCP或UDP端口号的组合。
第二个参数是一个指向特定协议的地址结构的指针,第三个参数是该地址结构的长度。对于TCP,调用bind函数可以指定一个端口号,或指定一个IP地址,也可以两者都指定,还可以都不指定。
listen函数:
当socket函数创建一个套接字时,它被假设为一个主动套接字,也就是说,它是一个将调用connect
发起连接的客户套接字。listen
函数把一个未连接的套接字转换成一个被动套接字,指示内核应接受指向该套接字的连接请求。根据TCP状态转换图,调用listen
导致套接字从CLOSED状态转换成LISTEN状态。
sockfd:成功创建的描述符
backlog:定义内核监听队列的最大长度。APUE中指出,backlog
只是一个提示,具体的数值实际上由系统决定。在内核版本2.2之前的Linux中,backlog
参数是指所有处于半连接状态(SYN_RCVD)和完全连接状态(ESTABLISHED)的socket的上限。但自内核版本2.2之后,它只表示处于完全连接状态的socket的上限,处于半连接状态的socket的上限则由/proc/sys/net/ipv4/tcp_max_syn_backlog
内核参数定义。backlog
参数的典型值是5(4.2BSD支持的最大值)。
accept函数:
sockfd是由socket函数返回的套接字描述符,参数addr和addrlen用来返回已连接的对端进程(客户端)的协议地址。
accept函数用于面向连接类型的套接字类型(SOCK_STREAM和SOCK_SEQPACKET)。accept函数将从连接请求队列中获得连接信息,创建新的套接字,并返回该套接字的文件描述符。新创建的套接字用于服务器与客户机的通信,而原来的套接字仍然处于监听状态。
accept函数的sockfd参数为监听的套接字描述符。addr参数为指向结构体sockaddr的指针。参数addrlen为addr参数指向的内存空间的长度。
其他函数请看上一篇文章,该代码由客户端改编而来