Tcp服务器的搭建流程:
- 创建套接字 socket
- 绑定ip 和端口号 bind
- 监听 listen
- 处理客户端连接请求 accept
- 通信
- read、write
- Recv、send
- Recvfrom、sendto
- 关闭套接字:close/shutdown(套接字,howto):howto:0(读端) 1(写端) 2(读写端,等同于 close());
代码如下:
#include <stdio.h>
#include <string.h>
#include <sys/types.h> /* See NOTES */ //man socket
#include <sys/socket.h>
#include <sys/socket.h> // man 7 ip
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <sys/socket.h> //man 3 inet_addr
#include <netinet/in.h>
#include <arpa/inet.h> //man 2 read
#include <unistd.h>
#define SIZE 1024
#define SERV_IP "0"
#define SERV_PORT 6666
int main(int argc,const char *argv[])
{
int listenfd; //用于保存监听套结字
int connfd ; //用于通信的套结字
int ret;
char recvbuf[SIZE] = {0};
//1、创建套结字 socket
listenfd = socket(AF_INET, SOCK_STREAM, 0); //AF_INET:IPV4协议 SOCK_STREAM:流式套结字
if(-1 == listenfd)
{
perror("socket");
return -1;
}
printf("socket %d ok\n", listenfd); //
//填充ip等信息到通用ip结构体
#if 0
struct sockaddr_in saddr ;
memset(&saddr, 0, sizeof(saddr)); // bzero(&saddr, sizeof(saddr));
saddr.sin_family = AF_INET; //IPV4 协议
saddr.sin_port = htons(6666);//端口号 :1024-49151
saddr.sin_addr.s_addr= inet_addr("192.168.16.100");
#else
struct sockaddr_in saddr = {
.sin_family = AF_INET,
.sin_port = htons(SERV_PORT),
.sin_addr.s_addr = inet_addr(SERV_IP)
};
#endif
//优化2:设置套结字属性 端口重用 setsockopt();
int opt = 1;
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
//2、绑定ip和端口a
socklen_t slen = sizeof(saddr);
ret = bind(listenfd, (struct sockaddr* )&saddr, slen);
if(-1 == ret)
{
perror("bind");
return -1;
}
printf("bind ok\n");
//3、监听
ret = listen(listenfd, 8);
if(-1 == ret)
{
perror("listen");
return -1;
}
printf("listen ok, wait for connect...\n");
//优化1:循环监听客户端
while(1)
{
//4、处理客户端请求
#if 0
//accept之后 监听套结字listenfd 转接 为新的 通信套结字 connfd 使用
connfd = accept(listenfd, NULL, NULL); //不关心客户端的ip和端口
printf("had client connect%d\n", connfd);
#else
//优化 3:关心客户端ip和端口了并打印
struct sockaddr_in caddr = {0};
// memset(caddr, 0, sizeof(caddr));
socklen_t clen = sizeof(caddr);
connfd = accept(listenfd, (struct sockaddr *)&caddr, &clen);
if(connfd == -1)
{
perror("accept");
return -1;
}
printf("client(%s:%d) had connected success\n", inet_ntoa(caddr.sin_addr), ntohs(caddr.sin_port) );
#endif
//5、通信
while(1)
{
memset(recvbuf, 0, sizeof(recvbuf));
int count = read(connfd, recvbuf, sizeof(recvbuf));
if(-1 == count)
{
perror("read");
return -1;
}
else if(0 == count)
{
printf("client quit\n");
break;
}
printf("recv:%s\n",recvbuf);
}
//6、关闭套结字退出
close(connfd);
}
close(listenfd);
return 0;
}