在我2014年2月份写的代码 code 的基础上,我进行了修改和增减功能。主要体现在下面几个方便:
- main函数不再是从程序开头写到结尾,而是分成了一个个较短的、功能明确的函数。
- 增加多线程支持
- 增删注释,换成中文注释
服务器端代码:
/*
* Filename: server.c
* version 1.1
* Author : Bruce Zhang
* Last edit time: Oct 16th, 2014
*/
#include <netinet/in.h> // for sockaddr_in
#include <sys/types.h> // for socket
#include <sys/socket.h> // for socket
#include <stdio.h> // for printf
#include <errno.h> // for errno
#include <stdlib.h> // for exit
#include <string.h> // for memset
#include <pthread.h> // for pthread
#define SERVER_PORT 6666
#define LENGTH_OF_LISTEN_QUEUE 20
#define BUFFER_SIZE 1024
struct sockaddr_in server_addr; // 设置一个服务器端的socket地址结构server_addr,代表服务器internet地址, 端口
int server_socket_fd; // 服务器端的文件描述符
char buffer_receive[BUFFER_SIZE]; // 定义接收字符的缓冲数组
char buffer_send[BUFFER_SIZE]; // 定义发送字符的缓冲数组
int fd_temp; // 文件描述符
pthread_t thread_send_fd; // 用于发送字符串的线程
pthread_t thread_receive_fd; // 用于接收字符串的线程
void init_server_socket() {
// buffer 清零
memset(buffer_receive, 0, BUFFER_SIZE);
memset(buffer_send, 0, BUFFER_SIZE);
// 初始化 server_addr,即服务器端的socket地址
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET; // sin_family指代协议族,在socket编程中只能是AF_INET
server_addr.sin_addr.s_addr = htons(INADDR_ANY); // sin_addr也是个结构体,里面存放着IP地址
server_addr.sin_port = htons(SERVER_PORT); // sin_port指的是端口号,主机字节序转化成网络字节序
}
void check_fd(int fd, char *info) {
if(fd == -1) {
printf(" %s failed...\n", info);
printf(" (errno: %d) %s\n", errno, strerror(errno));
exit(1);
}
}
// 接收数据 receive
void *thread_receive(void *arg) {
int new_socket_fd = *(int *)arg;
while(1) {
memset(buffer_receive, 0, BUFFER_SIZE);
int buflen = recv(new_socket_fd, buffer_receive, BUFFER_SIZE, 0);
check_fd(buflen, "receive");
if (buflen == 0)
continue;
printf("\nclient: %s", buffer_receive);
printf("\nI say: ");
// bye 结束会话
// trim(buffer_receive);
if(strcmp(buffer_receive, "bye") == 0) {
close(new_socket_fd); break;
}
sleep(1);
}
}
// 读取并发送数据 send
void *thread_send(void *arg) {
int new_socket_fd = *(int *)arg;
while(1) {
memset(buffer_send, 0, BUFFER_SIZE);
fgets(buffer_send, BUFFER_SIZE, stdin);
int buflen = send(new_socket_fd, buffer_send, sizeof(buffer_send), 0);
check_fd(buflen, "send");
}
}
void begin_conversation(int new_socket_fd) {
printf(" conversation detected\n\n");
int err1 = pthread_create(&thread_send_fd, NULL, thread_send, &new_socket_fd);
if(err1 != 0)
printf("%s\n",strerror(err1));
int err2 = pthread_create(&thread_receive_fd, NULL, thread_receive, &new_socket_fd);
if(err2 != 0)
printf("%s\n",strerror(err2));
}
int main(int argc, char const *argv[])
{
// 1. 初始化socket
init_server_socket();
// 2. 创建socket,原型是 int socket(int domain, int type, int protocol);
server_socket_fd = socket(AF_INET, SOCK_STREAM, 0);
check_fd(server_socket_fd, "create server socket");
// 3. 绑定(bind) server_socket_fd 和 server_addr 函数原型为: int bind(int sockfd,struct sockaddr *my_addr, int addrlen);
fd_temp = bind(server_socket_fd,(struct sockaddr*)&server_addr, sizeof(server_addr) );
check_fd(fd_temp, "bind");
// 4. 打开监听,原型是 int listen(int sockfd, int backlog); 第二个参数是等待队列的大小
fd_temp = listen(server_socket_fd, LENGTH_OF_LISTEN_QUEUE);
check_fd(fd_temp, "begin listening");
printf("welcome to chit-chat~ the server is listening for a guest \n");
// 5. 开始接收(accept)和 收发数据(receive && send)
while(1) {
struct sockaddr_in client_addr; // 此变量用来存放链接的客户端socket地址,和server_addr比较
socklen_t length = sizeof(client_addr);
// 如果没有连接请求,就等待到有连接请求--这是accept函数的特性
// accept函数把连接到的客户端信息填写到客户端的socket地址结构client_addr中
int new_socket_fd = accept(server_socket_fd, (struct sockaddr*)&client_addr, &length);
check_fd(new_socket_fd, "new socket accepted");
// 开始会话
begin_conversation(new_socket_fd);
}
close(thread_send_fd);
close(thread_receive_fd);
close(server_socket_fd);
return 0;
}
客户端代码:
/*
* Filename: client.c
* version 1.1
* Author : Bruce Zhang
* Last edit time: Oct 16th, 2014
*/
#include <netinet/in.h> // for sockaddr_in
#include <sys/types.h> // for socket
#include <sys/socket.h> // for socket
#include <stdio.h> // for printf
#include <errno.h> // for errno
#include <stdlib.h> // for exit
#include <string.h> // for memset
#include <pthread.h> // for pthread
#define SERVER_PORT 6666
#define BUFFER_SIZE 1024
int client_socket_fd;
struct sockaddr_in server_address;
socklen_t server_addr_length;
char buffer_receive[BUFFER_SIZE];
char buffer_send[BUFFER_SIZE];
int fd_temp;
pthread_t thread_send_fd; // 用于发送字符串的线程
pthread_t thread_receive_fd; // 用于接收字符串的线程
void check_fd(int fd, char *info) {
if(fd == -1) {
printf("%s failed...\n", info);
printf("(errno: %d) %s\n", errno, strerror(errno));
exit(1);
}
}
void init_server_socket(const char *argv[]) {
server_addr_length = sizeof(server_address);
memset(&server_address, 0, server_addr_length);
server_address.sin_family = AF_INET;
// aton = address to number 把字符串转化成32bits的二进制数字
if (inet_aton(argv[1],&server_address.sin_addr) == 0)
{
printf("输入的IP不合法 \n");
exit(1);
}
server_address.sin_port = htons(SERVER_PORT);
}
void say_hello() {
memset(buffer_receive, 0, sizeof(buffer_receive));
memset(buffer_send, 0, sizeof(buffer_send));
strcpy(buffer_send, "chit-chat begins ~_~");
fd_temp = send(client_socket_fd, buffer_send, sizeof(buffer_send), 0);
check_fd(fd_temp, "say hello");
}
// 接收数据 receive
void *thread_receive() {
while(1) {
memset(buffer_receive, 0, BUFFER_SIZE);
int buflen = recv(client_socket_fd, buffer_receive, BUFFER_SIZE, 0);
check_fd(buflen, "receive");
if (buflen == 0)
continue;
printf("\nserver: %s", buffer_receive);
printf("\nI say: ");
// bye 结束会话
// trim(buffer_receive);
if(strcmp(buffer_receive, "bye") == 0) {
close(client_socket_fd); break;
}
sleep(1);
}
}
// 读取并发送数据 send
void *thread_send() {
while(1) {
memset(buffer_send, 0, BUFFER_SIZE);
fgets(buffer_send, BUFFER_SIZE, stdin);
int buflen = send(client_socket_fd, buffer_send, sizeof(buffer_send), 0);
check_fd(buflen, "send");
}
}
void begin_conversation() {
printf(" conversation detected\n\n");
int err1 = pthread_create(&thread_send_fd, NULL, thread_send, NULL);
if(err1 != 0)
printf("%s\n",strerror(err1));
else
printf("send thread created\n");
int err2 = pthread_create(&thread_receive_fd, NULL, thread_receive, NULL);
if(err2 != 0)
printf("%s\n",strerror(err2));
else
printf("receive thread created\n");
}
int main(int argc, char const *argv[])
{
if (argc != 2) {
printf(" You must tell me the address of server! \n");
return 0;
}
// 创建 client_socket
client_socket_fd = socket(AF_INET,SOCK_STREAM,0);
check_fd(client_socket_fd, "creat socket");
// 初始化服务器的socket
init_server_socket(argv);
// 连接
fd_temp = connect(client_socket_fd, (struct sockaddr*) &server_address, server_addr_length);
check_fd(fd_temp, "connect");
// 试探一下能否连通
//say_hello();
printf("conversation received, chit-chat begins ~_~ \n");
begin_conversation();
pthread_join(thread_send_fd, NULL);
pthread_join(thread_receive_fd, NULL);
return 0;
}