pub.h文件
/*
* pub.h
*
* Created on: 2016年7月21日
* Author: Administrator
*/
#ifndef PUB_H_
#define PUB_H_
#include <stdio.h>
#include <stdlib.h>
void init_socket_client();
void catch_Signal(int Sign);
int signal1(int signo, void (*func)(int));
void socket_accept(int st);
int socket_create(int port);
#endif /* PUB_H_ */
pub.c
/*
* pub.c
*
* Created on: 2016年7月21日
* Author: Administrator
*/
#include "pub.h"
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <error.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#define BUFSIZE 1024
int socket_client[2];
int socket_create(int port)
{
int st = socket(AF_INET, SOCK_STREAM, 0);
int on = 1;
if (setsockopt(st, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1)
{
printf("setsockopt is failed %s\n", strerror(errno));
return 0;
}
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(st, (struct sockaddr *) &addr, sizeof(addr)) == -1)
{
printf("bind is failed %s\n", strerror(errno));
return 0;
}
if (listen(st, 300) == -1)
{
printf("listen is failed %s\n", strerror(errno));
return 0;
}
return st;
}
void catch_Signal(int Sign)
{
switch (Sign)
{
case SIGINT:
printf("signal SIGINT\n");
break;
}
}
int signal1(int signo, void (*func)(int))
{
struct sigaction act, oact;
act.sa_handler = func;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
return sigaction(signo, &act, &oact);
}
void init_socket_client()// 初始化int socket_client[2]数组
{
memset(socket_client, 0, sizeof(socket_client));
}
// 接收来自client发送的消息,index为0,代表接收到socket_client[0]消息,然后发送给socket_client[1]发送接收到的消息
// index为1,代表收到socket_client[1]消息,然后给socket_client[0]发送消息
// buf为发送消息内容,len为发送消息长度
void deliver(int index, const char *buf, ssize_t len)
{
ssize_t rc = 0;
if (index == 0)// 如果index为0,代表0给1发消息
{
if (socket_client[1] == 0)// 1不在
{
printf("%d:user not online\n", index);
}
else
{
rc = send(socket_client[1], buf, len, 0);// 消息下发给1
printf("send '%s'\nsend %u bytes\n", buf, rc);
if (rc <= 0)
{
if (rc == 0)
printf("send failed, disconn\n");
else
printf("send failed, %s\n", strerror(errno));
}
}
}
if (index == 1)// 如果index为1,代表1给0发消息
{
if (socket_client[0] == 0)// 0不在线
{
printf("%d:user not online\n", index);
}
else
{
rc = send(socket_client[0], buf, len, 0);// 消息下发给1
printf("send '%s'\nsend %u bytes\n", buf, rc);
if (rc <= 0)
{
if (rc == 0)
printf("send failed, disconn\n");
else
printf("send failed, %s\n", strerror(errno));
}
}
}
}
void socket_work(int index)
{
char buf[BUFSIZE];
ssize_t rc = 0;
while (1)
{
memset(buf, 0, sizeof(buf));
rc = recv(socket_client[index], buf, sizeof(buf), 0);
if (rc <= 0)// client连接断开
{
if (rc == 0)
printf("%d:recv disconn\n", index);
else
printf("%d:recv failed, %s\n", index, strerror(errno));
close(socket_client[index]);
socket_client[index] = 0;// 如果client的socket已经断开那么要置为零
break;
}
else
{
printf("%d:recv '%s'\nrecv %u bytes\n", index, buf, rc);
// index为0,代表接收到socket_client[0]消息,然后socket_client[1]消息BUFSIZE
// index为1,代表接收到socket_client[1]消息,然后socket_client[0]消息BUFSIZE
// buf为发送消息内容
deliver(index, buf, rc);
}
}
}
void *socket_contrl(void *arg)// server端的线程入口函数
{
int client_st = *(int *)arg;// 得到从accept函数返回的来自client端的socket描述符
free((int *)arg);
printf("contrl_thread is begin\n");
int index = 0;
if (socket_client[0] == 0)// 如果socket_client[0]空闲,就将来自client端的socket付给socket_client[0]
{
socket_client[0] = client_st;
}
else// 如果socket[1]空闲,九江client端的socket付给socket_client[1]
{
if (socket_client[1] == 0)
{
socket_client[1] = client_st;
index = 1;
}
else// socket_clien[0]socket_client[1]都不空闲
{
close(client_st);// socket_clien[2]两个成员都已经在线了,拒绝其他client连接
return NULL;
}
}
// 接收来自client端的链接,index为0代表接受来自socket_client[0]的消息
// index为1代表接收来自socket_client[1]的消息
socket_work(index);
printf("contrl_thread is end\n");
return NULL;
}
// 将addr转化为字符串
void sockaddr_toa(const struct sockaddr_in *addr, char *IPAddr)
{
unsigned char *p = (unsigned char *)&(addr->sin_addr.s_addr);
sprintf(IPAddr, "%u.%u.%u.%u", p[0], p[1], p[2], p[3]);
}
void socket_accept(int st)
{
pthread_t thr_d;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);// 设置线程属性可分离
struct sockaddr_in client_addr;
socklen_t len = sizeof(client_addr);
while (1)
{
memset(&client_addr, 0, sizeof(client_addr));
int client_st = accept(st, (void *)&client_addr, &len);// accept函数阻塞,知道
if (client_st == -1)
{
printf("accept failed %s\n", strerror(errno));
break;
}
else
{
char sIP[32];
memset(sIP, 0, sizeof(sIP));
sockaddr_toa(&client_addr, sIP);// 将IP地址转化为字符串
printf("accept by %s\n", sIP);
// 这里是多线程,如果用栈变量的话,可能会出现主线程退出后栈释放掉,但是子线程还在执行的情况
// 出了在主函数之外,都不能将栈变量传入多线程的函数中
int *tmp = malloc(sizeof(int));
*tmp = client_st;
// 只要accept到来自client端的socket,就启动一个线程,线程入口函数为socket_contrl
pthread_create(&thr_d, &attr, socket_contrl, tmp);
}
}
pthread_attr_destroy(&attr);
}
qqserver.c
/*
* qqserver.c
*
* Created on: 2016年7月21日
* Author: Administrator
*/
#include "pub.h"
int main(int arg, char *args[])
{
if (arg < 2)
{
printf("usage:qqserver port\n");
return 0;
}
int iport = atoi(args[1]);
if (iport == 0)
{
printf("port %d is invalid\n", iport);
return 0;
}
printf("qqserver is begin\n");
//signal1(SIGINT, catch_Signal);// 捕捉SIGINT消息
init_socket_client();// 初始化init_socket_client[2]数组
int st = socket_create(iport);// 建立server端socket,在iport指定的断口号上listen
if (st == 0)
return 0;
socket_accept(st);
close(st);
printf("qqserver is end\n");
return 0;
}
qqclient.c
/*
* qqclient.c
*
* Created on: 2016年7月21日
* Author: Administrator
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <pthread.h>
#define BUFSIZE 1024
void *socket_read(void *arg)
{
int st = *(int *)arg;
char buf[BUFSIZE];
while (1)
{
memset(buf, 0, sizeof(buf));
ssize_t rc = recv(st, buf, sizeof(buf), 0);
if (rc <= 0)
{
printf("recv failed, %s\n", strerror(errno));
break;
}
else
{
printf("recv '%s'\nrecv %u byte\n", buf, rc);
}
}
return NULL;
}
void *socket_write(void *arg)
{
int st = *(int *)arg;
char buf[BUFSIZE];
while (1)
{
memset(buf, 0, sizeof(buf));
read(STDIN_FILENO, buf, sizeof(buf));
int ilen = strlen(buf);
if (buf[ilen - 1] == '\n')
{
buf[ilen - 1] = 0;
}
ssize_t rc = send(st, buf, sizeof(buf), 0);
printf("send '%s'\nsend %u byte\n", buf, rc);
if (rc <= 0)
{
printf("send failed, %s\n", strerror(errno));
}
}
return NULL;
}
int socket_connect(const char *hostname, int iport)
{
int st = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(iport);
addr.sin_addr.s_addr = inet_addr(hostname);
if (connect(st, (struct sockaddr *)&addr, sizeof(addr)) == -1)
{
printf("connect failed %s\n", strerror(errno));
}
else
{
printf("connect success\n");
}
return st;
}
int main(int arg, char *args[])
{
if (arg < 3)
{
printf("usage:qqserver port\n");
return 0;
}
int iport = atoi(args[2]);
if (iport == 0)
{
printf("port %d is invalid\n", iport);
return 0;
}
printf("qqclient is begin\n");
int st = socket_connect(args[1], iport);
if (st == 0)
return 0;
pthread_t thr_read, thr_write;
pthread_create(&thr_read, NULL, socket_read, &st);// 启动读socket数据线程
pthread_create(&thr_write, NULL, socket_write, &st);// 启动写socket数据线程
pthread_join(thr_read, NULL);
//pthread_join(thr_write, NULL);// 如果等待thr_write退出,main函数可能被挂起
close(st);
printf("qqclient is end\n");
return 0;
}
makefile
.SUFFIXES:.c .o
CC=gcc
SRCS1=qqserver.c\
pub.c
SRCS2=qqclient.c\
pub.c
OBJS1=$(SRCS1:.c=.o)
OBJS2=$(SRCS2:.c=.o)
EXEC1=qqserver
EXEC2=qqclient
start: $(OBJS1) $(OBJS2)
$(CC) -o $(EXEC1) $(OBJS1) -lpthread
$(CC) -o $(EXEC2) $(OBJS2) -lpthread
@echo '----------------ok------------'
.c.o:
$(CC) -Wall -o $@ -c $<
clean:
rm -f $(OBJS)