目录
在linux中的网络编程中,TCP协议是我们最常用的几种协议之一,今天我们就使用TCP协议实现一个多线程的回复程序(echo服务器)。
总的来说就是使用C语言,在主线程中socket套接字一直处于监听的状态,如果有TCP客户端链接,就开启新的子线程来处理,接收来的数据并将收到的数据返回给发送者。
那么我们来看代码吧
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#include <stdlib.h>
void *TCP_client(void *arg);
int main(int argc, char const *argv[])
{
//sockfd监听套接字(不是用来和客户端通信 只是接受客户端的链接请求)
int sockfd = socket(AF_INET,SOCK_STREAM,0);
//服务器必须bind一个固定的port端口
struct sockaddr_in my_addr;
bzero(&my_addr,sizeof(my_addr));
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(atoi(argv[1]));
my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
int opt = 1;
// sockfd为需要端口复用的套接字
//设置端口复用后再次绑定相同的端口也可以成功
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const void *)&opt, sizeof(opt));
bind(sockfd,(struct sockaddr*)&my_addr,sizeof(my_addr));
//使用listen 由主动变被动 创建链接队列
listen(sockfd, 10);
//使用accept提取已完成链接的客户端
while(1)
{
struct sockaddr_in client_addr;
socklen_t len = sizeof(client_addr);
//阻塞
int new_fd = accept(sockfd, (struct sockaddr *)&client_addr, &len);
//new_fd 已连接套接字 代表和客户端的真正链接
//需要查看客户端信息
char ip_str[16]="";
inet_ntop(AF_INET, &client_addr.sin_addr.s_addr,ip_str,16);
printf("ip:%s port:%hu\n", ip_str, ntohs(client_addr.sin_port));
//创建一个单独的线程 服务于客户端
pthread_t tid;
pthread_create(&tid,NULL,TCP_client, (void *)new_fd);
pthread_detach(tid);
}
//关闭监听套接字
close(sockfd);
return 0;
}
void *TCP_client(void *arg)
{
int new_fd = (int)(long)arg;
//和客户端通信一下(echo服务器)客户端连接服务器 并发送数据给服务器 服务器收到数据 同时转发给客户端
char buf[128]="";
//收
int ret = recv(new_fd, buf,sizeof(buf),0);
//原样转发
send(new_fd,buf,ret,0);
//关闭已连接套接字
close(new_fd);
}