server.c
#include <netdb.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <signal.h>
#include <errno.h>
#include <time.h>
#include <pthread.h>
int sockfd;
void sig_handler(int signo)
{
if (signo == SIGINT) {
printf("server close\n");
/*关闭socket*/
close(sockfd);
exit(1);
}
}
void* th_fn(void* arg)
{
int fd = (int)arg;
/*和客户端进行读写操作(双向通信)*/
char buff[512];
while (1) {
memset(buff,0,sizeof(buff));
size_t size = 0;
if ((size = read(fd,buff,sizeof(buff))) <= 0) {
perror("server read error");
continue;
} else {
printf("%s",buff);
//将读取到的数据在发送回客户端
if (write(fd,buff,sizeof(buff)) < 0) {
perror("server write data to client error");
}
}
}
return (void*)0;
}
int main(int argc,char* argv[])
{
if (argc<2) {
printf("usage:%s #port\n",argv[0]);
exit(0);
}
if (signal(SIGINT,sig_handler) == SIG_ERR) {
perror("signal sigint error");
exit(1);
}
/* 步骤1:创建socket套接字
* 注:socket创建在内核中,是一个结构体
* AF_INET:IPV4
* SOCK_STREAM:tcp协议
* */
sockfd = socket(AF_INET,SOCK_STREAM,0);
/*
* 步骤2:调用bind函数将socket和地址(包括ip,port)进行绑定
* */
struct sockaddr_in serveraddr;
memset(&serveraddr,0,sizeof(serveraddr));
//往地址中填入ip,port,internet地址族类型
serveraddr.sin_family = AF_INET;//IPV4
serveraddr.sin_port = htons(atoi(argv[1]));//port
serveraddr.sin_addr.s_addr = INADDR_ANY;
if (bind(sockfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr))<0) {
perror("bind error");
exit(1);
}
/*
* 步骤3:调用listen函数启动监听(指定port监听)
* 通知系统接受来自客户端的连接请求(将接受到的客户端连接请求放置到对应的队列中)
* 第二个参数:允许连接的客户端数量
* */
if (listen(sockfd,10)<0) {
perror("listen error");
exit(1);
}
/*
* 步骤4:调用accept函数从队列中获得一个客户端的请求连接,并返回新的socket描述副
* 注意:若没有客户端连接,调用此函数后会阻塞直到获得一个客户端连接
* */
struct sockaddr_in clientaddr;
socklen_t clientaddr_len = sizeof(clientaddr);
//设置线程的分离属性
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
while (1) {
//主控线程负责调用accept去获得客户端的连接
int fd = accept(sockfd,(struct sockaddr*)&clientaddr,&clientaddr_len);
if (fd<0) {
perror("accept error");
continue;
}
/*
* 步骤5:启动子线程调用IO函数(read/write)和连接的客户端进行双向通信
* */
pthread_t th;
int err;
if ((err = pthread_create(&th,&attr,th_fn,(void*)fd)) != 0) {
perror("pthread create error");
}
pthread_attr_destroy(&attr);
}
return 0;
}
client.c
#include <netdb.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>
#include <unistd.h>
#include <stdio.h>
int main(int argc,char* argv[])
{
if (argc < 3) {
printf("usage:%s ip port\n",argv[0]);
exit(1);
}
/*步骤1:创建socket*/
int sockfd = socket(AF_INET,SOCK_STREAM,0);
if(sockfd<0)
{
perror("socket error");
exit(1);
}
struct sockaddr_in serveraddr;
memset(&serveraddr,0,sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(atoi(argv[2]));
//将ip地址转换成网络字节序后填入serveraddr中
inet_pton(AF_INET,argv[1],&serveraddr.sin_addr.s_addr);
/*步骤2:客户端调用connect函数连接服务器端*/
if (connect(sockfd,(struct sockaddr*)&serveraddr,sizeof(serveraddr)) < 0) {
perror("connect error");
exit(1);
}
/*步骤3:调用IO函数(read/write)和服务器端进行双向通信*/
char buff[1024];
size_t size;
while (1) {
memset(buff,0,sizeof(buff));
size = read(STDIN_FILENO,buff,sizeof(buff)); // 读取客户输入数据
if (size < 0) {
continue;
}
// buff[size-1] = '\0';
//客户输入数据读取成功,将数据发往服务端
if (write(sockfd,buff,sizeof(buff)) > 0) {
memset(buff,0,sizeof(buff));
if (read(sockfd,buff,sizeof(buff)) > 0) {
write(STDOUT_FILENO,buff,sizeof(buff));
}
}
}
return 0;
}