
这里写目录标题
- tcp_server.c
- tcp_client.c
- 代码说明:
- 来源:微信公众号:图控大叔
代码
tcp_server.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <strings.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
struct fifo_data
{
char fifo_name[32];
char fifo_type[32];
char fifo_buff[1024];
unsigned long long data_len;
int ret;
};
struct msg_data
{
int data_size;
char name[16];
struct fifo_data myfifo;
char buffer[1024];
};
struct client_fd_sql{
int client_fd[50];
int last;
};
typedef struct client_info{
int client_fd;
char name[256];
char ip[16];
short port;
pthread_t tid;
struct client_info *next;
}client_info_node;
#define list_for_each(head, pos)\
for(pos=head->next; pos!=NULL; pos=pos->next)
static client_info_node *request_client_info_node(const client_info_node *info)
{
client_info_node *new_node;
new_node = malloc(sizeof(client_info_node));
if(new_node == NULL)
{
perror("申请客户端节点异常");
return NULL;
}
if(info != NULL)
*new_node = *info;
new_node->next = NULL;
return new_node;
}
static inline void insert_client_info_node_to_link_list(client_info_node *head, client_info_node *insert_node)
{
client_info_node *pos;
for(pos=head; pos->next != NULL; pos=pos->next);
pos->next = insert_node;
}
void *client_thread(void *arg)
{
int client_fd;
struct msg_data recv_msg;
ssize_t recv_size, send_size;
client_info_node *pos, *list_head = arg;
list_for_each(list_head, pos)
{
if(pthread_self() == pos->tid)
{
client_fd = pos->client_fd;
break;
}
}
while(1)
{
bzero(&recv_msg, sizeof(recv_msg));
recv_size = recv(client_fd, &recv_msg, sizeof(recv_msg), 0);
if(recv_size == -1)
{
perror("接受数据异常");
break;
}
else if(recv_size == 0)
{
break;
}
list_for_each(list_head, pos)
{
if(pos->client_fd == client_fd)
continue;
printf("转发数据给端口号为%hu\n", pos->port);
send_size = send( pos->client_fd, &recv_msg, sizeof(recv_msg), 0);
if(send_size == -1)
break;
}
printf("接收到来自与客户端%ld个字节的数据:%s\n", recv_size, recv_msg.buffer);
}
return NULL;
}
int main(void)
{
int skt_fd;
int retval;
client_info_node *list_head, *new_node;
client_info_node cache_client_info;
ssize_t recv_size, send_size;
list_head = request_client_info_node(NULL);
skt_fd = socket( AF_INET, SOCK_STREAM, 0);
if(skt_fd == -1)
{
perror("申请套接字失败");
return -1;
}
int sw = 1;
retval = setsockopt(skt_fd, SOL_SOCKET, SO_REUSEADDR, &sw, sizeof(sw));
struct sockaddr_in native_addr;
native_addr.sin_family = AF_INET;
native_addr.sin_port = htons(6666);
native_addr.sin_addr.s_addr = htonl(INADDR_ANY);
retval = bind( skt_fd, (struct sockaddr *)&native_addr, sizeof(native_addr));
if(retval == -1)
{
perror("绑定套接字地址失败");
goto bind_socket_err;
}
retval = listen(skt_fd, 50);
if(retval == -1)
{
perror("设置最大连接数失败");
goto set_listen_err;
}
int client_fd;
struct sockaddr_in client_addr;
socklen_t sklen = sizeof(client_addr);
struct client_fd_sql client_fds = {.last=-1};
int i;
int max_fd = skt_fd;
fd_set readfds;
FD_ZERO(&readfds);
struct msg_data recv_msg;
while(1)
{
FD_SET(0, &readfds);
FD_SET(skt_fd, &readfds);
for(i=0; i<=client_fds.last; i++)
{
FD_SET(client_fds.client_fd[i], &readfds);
}
retval = select(max_fd+1, &readfds, NULL, NULL, NULL);
if(retval == -1)
{
perror("复用等待异常");
goto select_err;
}
else if(retval == 0)
{
printf("服用等待超时\n");
}
else if(retval)
{
for(i=0; i<=client_fds.last; i++)
{
if(FD_ISSET(client_fds.client_fd[i], &readfds))
{
bzero(&recv_msg, sizeof(recv_msg));
recv_size = recv(client_fds.client_fd[i], &recv_msg, sizeof(recv_msg), 0);
if(recv_size == -1)
{
perror("读取数据异常");
continue;
}else if(recv_size == 0)
{
printf("客户端断开链接\n");
memcpy(client_fds.client_fd+i, client_fds.client_fd+i+1, client_fds.last-i);
client_fds.last--;
break;
}
client_info_node *pos;
list_for_each(list_head, pos)
{
if(pos->client_fd == client_fds.client_fd[i])
continue;
printf("转发数据给端口号为%hu\n", pos->port);
send_size = send( pos->client_fd, &recv_msg, sizeof(recv_msg), 0);
if(send_size == -1)
break;
}
printf("接收到来自与客户端%ld个字节的数据:%s\n", recv_size, recv_msg.buffer);
}
}
if(FD_ISSET(0, &readfds))
{
bzero(&recv_msg, sizeof(recv_msg));
scanf("%s", recv_msg.buffer);
printf("从键盘当中获取到:%s\n", recv_msg.buffer);
}
if(FD_ISSET(skt_fd, &readfds))
{
cache_client_info.client_fd = accept(skt_fd, (struct sockaddr *)&client_addr, &sklen);
if(cache_client_info.client_fd == -1)
{
perror("客户端链接失败");
goto client_connect_err;
}
strcpy(cache_client_info.ip, inet_ntoa(client_addr.sin_addr));
cache_client_info.port = ntohs(client_addr.sin_port);
new_node = request_client_info_node(&cache_client_info);
insert_client_info_node_to_link_list(list_head, new_node);
printf("服务器:客户端连接成功\n");
printf("客户端信息:\n客户端IP为%s,端口号为%hu\n", cache_client_info.ip, cache_client_info.port);
client_fds.last++;
client_fds.client_fd[client_fds.last] = client_fd;
max_fd = max_fd>client_fd ? max_fd : client_fd;
pthread_create(&(new_node->tid), NULL, client_thread, list_head);
}
}
}
close(client_fd);
close(skt_fd);
return 0;
socket_recv_err:
select_err:
close(client_fd);
client_connect_err:
set_listen_err:
bind_socket_err:
close(skt_fd);
return -1;
}
tcp_client.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <strings.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#define DEST_FILE "./06.rar"
int fd1;
int fd2;
struct fifo_data
{
char fifo_name[32];
char fifo_type[32];
char fifo_buff[1024];
unsigned long long data_len;
int ret;
};
struct msg_data
{
int data_size;
char name[16];
struct fifo_data myfifo;
char buffer[1024];
};
void *recv_data(void *arg)
{
int skt_fd = *(int *)arg;
struct msg_data send_msg, recv_msg;
ssize_t recv_size;
ssize_t send_size;
printf("recv_data\n");
while(1)
{
bzero(&(send_msg.myfifo.fifo_buff), sizeof(send_msg.myfifo.fifo_buff));
bzero(&recv_msg, sizeof(recv_msg));
recv_size = recv(skt_fd, &recv_msg, sizeof(recv_msg), 0);
if(recv_size == -1)
{
perror("接受数据异常");
break;
}
printf("data is %llu Byte\n",recv_msg.myfifo.data_len);
send_msg.myfifo.ret = read(fd1, send_msg.myfifo.fifo_buff, 1024);
if(send_msg.myfifo.ret == 0)
{
printf("copy %llu Byte , read has finshed!\n", send_msg.myfifo.data_len);
send_msg.data_size = sizeof(send_msg);
send_size = send( skt_fd, &send_msg, send_msg.data_size, 0);
if(send_size == -1)
printf("发送出错\n");
break;
}
send_msg.myfifo.data_len = send_msg.myfifo.ret + send_msg.myfifo.data_len;
send_msg.data_size = sizeof(send_msg);
send_size = send( skt_fd, &send_msg, send_msg.data_size, 0);
if(send_size == -1)
printf("发送出错\n");
}
return NULL;
}
void *recv_data22(void *arg)
{
int skt_fd = *(int *)arg;
struct msg_data send_msg, recv_msg;
ssize_t recv_size;
ssize_t send_size;
printf("recv_data22\n");
while(1)
{
bzero(&recv_msg, sizeof(recv_msg));
recv_size = recv(skt_fd, &recv_msg, sizeof(recv_msg), 0);
if(recv_size == -1)
{
perror("接受数据异常");
break;
}
if(recv_msg.myfifo.ret == 0)
{
printf("文件传输完毕,长度为%llu\n", recv_msg.myfifo.data_len);
close(fd2);
break;
}
write(fd2, recv_msg.myfifo.fifo_buff, recv_msg.myfifo.ret);
printf("data is %llu Byte\n",recv_msg.myfifo.data_len);
send_msg.myfifo.data_len = send_msg.myfifo.ret + send_msg.myfifo.data_len;
send_msg.data_size = sizeof(send_msg);
send_size = send( skt_fd, &send_msg, send_msg.data_size, 0);
if(send_size == -1)
printf("发送出错\n");
}
return NULL;
}
int main(int argc, const char *argv[])
{
int skt_fd;
int retval;
skt_fd = socket( AF_INET, SOCK_STREAM, 0);
if(skt_fd == -1)
{
perror("申请套接字失败");
return -1;
}
struct sockaddr_in srv_addr;
srv_addr.sin_family = AF_INET;
srv_addr.sin_port = htons(6666);
srv_addr.sin_addr.s_addr = inet_addr(argv[1]);
retval = connect(skt_fd, (struct sockaddr *)&srv_addr, sizeof(srv_addr));
if(retval == -1)
{
perror("客户端连接到服务器失败\n");
goto connect_server_err;
}
printf("客户端:连接服务器成功\n");
struct msg_data send_msg;
stpcpy(send_msg.name, argv[2]);
ssize_t send_size;
printf("接收:1\n还是发送:2\n");
scanf("%d", &retval);
if(retval == 1)
{
fd2 = open("./07.rar", O_WRONLY | O_CREAT | O_TRUNC, 0777);
pthread_t tid;
pthread_create(&tid, NULL, recv_data22, &skt_fd);
}
else
{
fd1 = open(DEST_FILE, O_RDONLY);
if(fd1 == -1)
{
printf("open %s failed! : \n", DEST_FILE);
return -1;
}
send_msg.myfifo.data_len = 0;
send_msg.myfifo.ret = read(fd1, send_msg.myfifo.fifo_buff, 1024);
printf("%d \n", send_msg.myfifo.ret);
send_msg.myfifo.data_len = send_msg.myfifo.ret + send_msg.myfifo.data_len;
send_msg.data_size = sizeof(send_msg);
send_size = send( skt_fd, &send_msg, send_msg.data_size, 0);
if(send_size == -1)
printf("发送出错\n");
pthread_t tid;
pthread_create(&tid, NULL, recv_data, &skt_fd);
}
while(1)
{
bzero(&(send_msg.buffer), sizeof(send_msg.buffer));
scanf("%s", send_msg.buffer);
send_msg.data_size = sizeof(send_msg);
send_size = send( skt_fd, &send_msg, send_msg.data_size, 0);
if(send_size == -1)
break;
}
close(skt_fd);
return 0;
connect_server_err:
close(skt_fd);
return -1;
}
代码说明:
1、服务器只是负责转发消息
2、客户端已经进行端口复用设置
3、需要发送的文件名路径已经设置好了,测试的需要自己更改
4、该客户端代码匆忙上线,只有简陋的文件发送功能。
公众号:图控大叔