一、TCP 服务器的创建
在 Linux 上创建一个简单的 tcp 服务器步骤如下:
①创建套接字
②将套接字绑定到 IP 地址和端口号
③监听来自客户端的连接
④接受连接并创建新的套接字用于与客户端通信
⑤通过新建的套接字发送和接收数据
⑥关闭套接字
流程框图如下:

根据以上介绍可以创建tcp server的示例,分为服务器-单客户端和服务器-多客户端。
二、服务器-单客户端示例
tcp server示例代码如下:
- #include
- #include
- #include
- #include
- #include
//struct sockaddr_in - #include
//inet_addr() - #include
//close() -
-
-
-
- #define MY_PRINTF(argv) do{\
- printf("file:%s --- function:%s --- line:%d\r\n",__FILE__,__FUNCTION__,__LINE__);\
- printf("%s\r\n",argv);\
- }while(0);
- #define MYPORT 5000
- //tcp server demo
- int main(int argc,char *argv[])
- {
- int sockefd;
- int sockenewfd;
- int ret;
- int enable=1;
-
-
- struct sockaddr_in my_addr;//本地地址-服务器
-
-
- struct sockaddr_in remote_addr;//远端地址-客户端
- int remote_addr_len;
-
-
- char buf[1024];
-
-
- sockefd=socket(AF_INET,SOCK_STREAM,0);// 套接字
- if(sockefd<0)
- {
- MY_PRINTF("socket err !! ");
- return -1;
- }
- if (setsockopt(sockefd, SOL_SOCKET, SO_REUSEADDR, (char *) &enable, sizeof(enable)) == -1)
- {
- close(sockefd);
- MY_PRINTF(" setsockopt err !! ");
- return -1;
- }
- MY_PRINTF("socket ok !! ");
-
-
- //本地地址
- my_addr.sin_family=AF_INET;
- my_addr.sin_port=htons(MYPORT);//0:随机端口
- my_addr.sin_addr.s_addr=INADDR_ANY;//inet_addr("192.168.164.157");//INADDR_ANY:本机 ip // inet_addr():IP 地址的字符串转换成一个无符号长整型
- bzero(my_addr.sin_zero,sizeof(my_addr.sin_zero));
-
-
-
-
- ret=bind(sockefd,(struct sockaddr*)&my_addr,sizeof(struct sockaddr));//绑定 //转换数据类型
- if(ret<0)
- {
- close(sockefd);
- MY_PRINTF("bind err !! ");
- return -1;
- }
- MY_PRINTF("bind ok !! ");
-
-
- ret=listen(sockefd,5);//监听
- if(ret<0)
- {
- close(sockefd);
- MY_PRINTF("listen err !! ");
- return -1;
- }
- MY_PRINTF("listen ok !! ");
-
-
- sockenewfd=accept(sockefd,(struct sockaddr *)&remote_addr,&remote_addr_len);//获取连接的新套接字
- if(sockenewfd<0)
- {
- close(sockefd);
- MY_PRINTF("accept err !! ");
- return -1;
- }
- MY_PRINTF("accept ok !! ");
-
-
- printf("%d\r\n",ntohs(remote_addr.sin_port)); //端口号
- printf("%s\r\n",inet_ntoa(remote_addr.sin_addr));//ip地址 //转换为字符串形式以 数字.数字.数字.数字 的格式显 示出来
-
-
- for(;;)
- {
- ret=recv(sockenewfd,buf,sizeof(buf),0);//接收
- if(ret<0)
- {
- close(sockenewfd);
- MY_PRINTF("recv err !! ");
- break;
- }
- else if(ret==0)
- {
- close(sockenewfd);
- MY_PRINTF("close !! ");
- perror("close sockenewfd");
- break;
- }
- MY_PRINTF("recv ok !! ");
- MY_PRINTF(buf);
-
-
- ret=send(sockenewfd,buf,ret,0);//发送 等价于write(sockenewfd,buf,ret);
- if(ret<0)
- {
- MY_PRINTF("send err !! ");
- }
- MY_PRINTF("send ok !! ");
- MY_PRINTF(buf);
- }
-
-
-
-
- close(sockefd);//关闭
- perror("close sockefd");
- return0;
-
-
- }
程序运行只允许单个客户端连接通讯。测试如下:
服务端启动,等待连接,如下:

客户端连接,如下:

服务端获取到客户端连接,如下:

客户端发送数据,并接收到服务端返回,如下:

服务端显示:

三、服务器-多客户端
这里介绍两种方法,方法一:使用多线程;方法二:使用select方法。
①方法一多线程,测试代码如下:
- #include
- #include
- #include
- #include
- #include
//struct sockaddr_in - #include
//inet_addr() - #include
//close() -
-
-
-
- #define MY_PRINTF(argv) do{\
- printf("file:%s --- function:%s --- line:%d\r\n",__FILE__,__FUNCTION__,__LINE__);\
- printf("%s\r\n",argv);\
- }while(0);
- #define MYPORT 5000
- //tcp server demo
-
-
-
-
- void *myfun_thread(void *socketInfo)
- {
- char buf[1024];
- int ret;
- int sockenewfd=(int)socketInfo;
-
-
- for(;;)
- {
- ret=recv(sockenewfd,buf,sizeof(buf),0);//接收
- if(ret<0)
- {
- close(sockenewfd);
- MY_PRINTF("recv err !! ");
- perror("close sockenewfd");
- break;
- }
- else if(ret==0)
- {
- close(sockenewfd);
- MY_PRINTF("close !! ");
- perror("close sockenewfd");
- break;
- }
- MY_PRINTF("recv ok !! ");
- MY_PRINTF(buf);
-
-
- ret=send(sockenewfd,buf,ret,0);//发送 等价于write(sockenewfd,buf,ret);
- if(ret<0)
- {
- MY_PRINTF("send err !! ");
- }
- MY_PRINTF("send ok !! ");
- MY_PRINTF(buf);
- }
- pthread_exit(NULL);
-
-
- }
-
-
- int main(int argc,char *argv[])
- {
- int sockefd;
- int sockenewfd;
- int ret;
- int enable=1;
- pthread_t threadRx;
- struct sockaddr_in my_addr;//本地地址-服务器
-
-
- struct sockaddr_in remote_addr;//远端地址-客户端
- int remote_addr_len;
-
-
-
-
-
- sockefd=socket(AF_INET,SOCK_STREAM,0);// 套接字
- if(sockefd<0)
- {
- MY_PRINTF("socket err !! ");
- return -1;
- }
- if (setsockopt(sockefd, SOL_SOCKET, SO_REUSEADDR, (char *) &enable, sizeof(enable)) == -1)
- {
- close(sockefd);
- MY_PRINTF(" setsockopt err !! ");
- return -1;
- }
- MY_PRINTF("socket ok !! ");
-
-
- //本地地址
- my_addr.sin_family=AF_INET;
- my_addr.sin_port=htons(MYPORT);//0:随机端口
- my_addr.sin_addr.s_addr=INADDR_ANY;//inet_addr("192.168.164.157");//INADDR_ANY:本机 ip // inet_addr():IP 地址的字符串转换成一个无符号长整型
- bzero(my_addr.sin_zero,sizeof(my_addr.sin_zero));
-
-
-
- ret=bind(sockefd,(struct sockaddr*)&my_addr,sizeof(struct sockaddr));//绑定 //转换数据类型
- if(ret<0)
- {
- close(sockefd);
- MY_PRINTF("bind err !! ");
- return -1;
- }
- MY_PRINTF("bind ok !! ");
-
-
- ret=listen(sockefd,5);//监听
- if(ret<0)
- {
- close(sockefd);
- MY_PRINTF("listen err !! ");
- return -1;
- }
- MY_PRINTF("listen ok !! ");
-
-
- while(1)
- {
- sockenewfd=accept(sockefd,(struct sockaddr *)&remote_addr,&remote_addr_len);//获取连接的新套接字
- if(sockenewfd<0)
- {
- MY_PRINTF("accept err !! ");
- break;
- }
- MY_PRINTF("accept ok !! ");
-
-
- printf("%d\r\n",ntohs(remote_addr.sin_port)); //端口号
- printf("%s\r\n",inet_ntoa(remote_addr.sin_addr));//ip地址 //转换为字符串形式以 数字.数字.数字.数字 的格式显 示出来
- pthread_create(&threadRx, NULL, myfun_thread, (void *)sockenewfd);
- sleep(1);
- }
- close(sockefd);//关闭
- perror("close sockefd");
- return 0;
-
-
- }
测试结果:
服务端:

客户端:
