Socket实现聊天发文件
来源:互联网 发布:国家电网数据运维 编辑:程序博客网 时间:2024/05/24 04:47
client.c
#define _WINSOCK_DEPRECATED_NO_WARNINGS#define _CRT_SECURE_NO_WARNINGS#include <stdio.h> #include <stdlib.h> #include <string.h> #include <WinSock2.h> #include <pthread.h>#include <windowsx.h>#pragma comment(lib, "WS2_32")#define BUFF_LEN 1024/* 预设服务器地址 */#define SERVER "127.0.0.1"/* 预设端口号*/#define PORT 12345enum MSG_TYPE{ MSG_CHAT = 0, MSG_FILE_NAME, MSG_FILE_CONTENT, MSG_FILE_END};void showMenu(){ printf("1. 聊天\n"); printf("2. 发送文件\n");}DWORD WINAPI processRead(LPVOID pM){ SOCKET s = (SOCKET)pM; int cmd = 0; while (1) { cmd = 0; showMenu(); scanf("%d", &cmd); fflush(stdin); switch (cmd) { case 1: { char buffer[BUFF_LEN]; printf("请输入聊天信息: \n"); scanf("%s", buffer); MSG_TYPE type = MSG_CHAT; int len = strlen(buffer) + 1; char *msg = (char *)malloc(strlen(buffer) + 1 + 2 * sizeof(int)); //从源src所指的内存地址的起始位置开始拷贝n个字节 //到目标dest所指的内存地址的起始位置中 memcpy(msg, &type, sizeof(type)); memcpy(msg+sizeof(type), &len, sizeof(len)); memcpy(msg + 2*sizeof(type), buffer, len); //第一个参数指定发送端套接字描述符; //第二个参数指明一个存放应用程序要发送数据的缓冲区; //第三个参数指明实际要发送的数据的字节数; //第四个参数一般置0。 send(s, msg, strlen(buffer) + 1 + 2 * sizeof(int), 0); free(msg); } break; case 2: { char buffer[BUFF_LEN]; printf("请输入传输文件名: \n"); scanf("%s", buffer); FILE *fp = fopen(buffer, "r"); if (fp == NULL) { printf("文件不存在或者发生未知错误\n"); break; } MSG_TYPE type = MSG_FILE_NAME;//MSG_FILE_NAME为1 int len = strlen(buffer) + 1; char *msg = (char *)malloc(strlen(buffer) + 1 + 2 * sizeof(int)); memcpy(msg, &type, sizeof(type)); memcpy(msg + sizeof(type), &len, sizeof(len)); memcpy(msg + 2 * sizeof(type), buffer, len); send(s, msg, strlen(buffer) + 1 + 2 * sizeof(int), 0); free(msg); while (1) { if (feof(fp)) { Sleep(100); type = MSG_FILE_END;//MSG_FILE_END 3 send(s, (char *)&type, sizeof(type), 0); printf("文件发送成功\n"); break; } else { memset(buffer, BUFF_LEN, 0); //buffer 用于接收数据的内存地址 //size 要读的每个数据项的字节数,单位是字节 //count 要读count个数据项,每个数据项size个字节. //stream 输入流 int ret = fread(buffer, 1, BUFF_LEN - 1, fp); if (ret < 0) printf("read error\n, %d\n", ret); printf("file ret %d\n", ret); buffer[ret] = '\0'; printf("buffer read : %s\n", buffer); MSG_TYPE t = MSG_FILE_CONTENT;//MSG_FILE_CONTENT 2 int ll = strlen(buffer) + 1; char *msg = (char *)malloc(ll + 2 * sizeof(int)); memset(msg, ll, 0); memcpy(msg, &t, sizeof(type)); memcpy(msg + sizeof(type), &ll, sizeof(len)); memcpy(msg + 2 * sizeof(type), buffer, ll); //send(s, msg, strlen(msg) + 1, 0); send(s, msg, ll + 2 * sizeof(int), 0); free(msg); } } } break; default: break; } } return 0;}DWORD WINAPI processWrite(LPVOID pM){ FILE *fp; SOCKET s = (SOCKET)pM; char buffer[BUFF_LEN] = { '\0' }; while (1) { memset(buffer, BUFF_LEN, 0); //第一个参数指定接收端套接字描述符; //第二个参数指明一个缓冲区,该缓冲区用来存放recv函数接收到的数据; //第三个参数指明buf的长度; //第四个参数一般置0。 recv(s, buffer, BUFF_LEN, 0); MSG_TYPE type; int len; memcpy(&type, buffer, sizeof(int)); if (type == MSG_FILE_END) { fclose(fp); printf("文件接收成功\n"); continue; } memcpy(&len, buffer + sizeof(int), sizeof(int)); char *msg = (char *)malloc(len); memset(msg, len, 0); memcpy(msg, buffer + 2 * sizeof(type), len); if (type == MSG_CHAT) { printf(" : %s\n", msg); } else if (type == MSG_FILE_NAME) { printf("文件名: %s\n", msg); fp = fopen(msg, "w"); } else //if(type == MSG_FILE_CONTENT) { printf("写文件\n"); if (fp != NULL) { printf("recv : %s\n", msg); fwrite(msg, 1, len - 1, fp); } } free(msg); } return 0;}int main(int argc, char *argv[]){ SOCKET client_sockfd; int len; struct sockaddr_in address; char server[UCHAR_MAX]; int result; if (argc > 1) { strcpy(server, argv[1]); } else { strcpy(server, SERVER); } // 初始化socket dll WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { printf("Init socket dll error!"); exit(1); } if ((client_sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("socket() 失败"); exit(EXIT_FAILURE); } address.sin_family = AF_INET; address.sin_addr.s_addr = inet_addr(SERVER); address.sin_port = htons(PORT); len = sizeof(address); if ((result = connect(client_sockfd, (struct sockaddr *) &address, len)) < 0) { perror("connect() 呼叫失敗"); closesocket(client_sockfd); exit(EXIT_FAILURE); } else { printf("连接成功...\n"); } HANDLE handle1 = CreateThread(NULL, 0, processRead, (LPVOID)client_sockfd, 0, NULL); HANDLE handle2 = CreateThread(NULL, 0, processWrite, (LPVOID)client_sockfd, 0, NULL); WaitForSingleObject(handle1, INFINITE); WaitForSingleObject(handle2, INFINITE); CloseHandle(handle1); CloseHandle(handle2); closesocket(client_sockfd); //释放winsock库 WSACleanup(); system("pause"); return 0;}
server.c
#define _CRT_SECURE_NO_WARNINGS#define _WINSOCK_DEPRECATED_NO_WARNINGS#include <stdio.h> #include <stdlib.h> #include <string.h> #include <WinSock2.h> #include <Ws2tcpip.h>#define PORT 12345 //端口#pragma comment(lib, "WS2_32") //库#define BUFF_LEN 1024int main(int argc, char *argv[]) { WSADATA wsaData; //windows下结构信息 SOCKET server_sockfd, client_sockfd; int on = 1; int server_len, client_len; struct sockaddr_in server_address; //数据结构 struct sockaddr_in client_address; int result; fd_set readfds, testfds;//select int fdmax; char buf[BUFF_LEN]; char tmp[BUFF_LEN]; char msg[BUFF_LEN]; timeval tv; tv.tv_sec = 0; //秒 tv.tv_usec = 500; // 微秒 100 500 int j; // 初始化socket dll ,请求2.2的版本 if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { printf("Init socket dll error!"); exit(1); } // 创建socket // 第一个参数,指定地址簇(TCP/IP只能是AF_INET,也可写成PF_INET) // 第二个,选择套接字的类型(流式套接字),第三个,特定地址家族相关协议(0为自动) server_sockfd = socket(AF_INET, SOCK_STREAM, 0); if (server_sockfd == INVALID_SOCKET) { printf("socket() 失败"); exit(EXIT_FAILURE); } u_long u1 = 1; //控制套接口的模式, //FIONBIO 非阻塞设置,非零;阻塞设置,零; ioctlsocket(server_sockfd, FIONBIO, (u_long*)& u1); //sin_family表示地址族,对于IP地址,sin_family成员将一直是AF_INET。 //sin_port指定将要分配给套接字的端口。 //sin_addr给出套接字的主机IP地址。 //将IP地址指定为INADDR_ANY,允许套接字向任何分配给本地机器的IP地址发送或接收数据。 server_address.sin_family = AF_INET; server_address.sin_addr.s_addr = htonl(INADDR_ANY); server_address.sin_port = htons(PORT); server_len = sizeof(server_address); //绑定socket和服务端(本地)地址 if (bind(server_sockfd, (sockaddr *)&server_address, server_len) == SOCKET_ERROR) { printf("Server Bind Failed: %d", WSAGetLastError()); exit(1); } //监听 if (listen(server_sockfd, 10) == -1) { printf("Server Listen Failed: %d", WSAGetLastError()); exit(1); } FD_ZERO(&readfds); //将 sockset 清空 FD_SET(server_sockfd, &readfds);//把 sockfd 加入到 sockset 集合中 FD_ZERO(&testfds);//将 sockset 清空 memset(&msg, BUFF_LEN, 0); memset(&tmp, BUFF_LEN, 0); /* 记录目前fd的数量 */ fdmax = server_sockfd; printf("服务器已经启动,等待客户上线\n"); for (;;) { int fd = 0; /* 复制编号 */ testfds = readfds;//每次在调用select前一定要更新一次 /* 使用 select() 实现多人聊天 */ //这里只监控了读取功能 result = select(0, &testfds, NULL, NULL, &tv); if (result < 0) { perror("服务器发生问题\n"); exit(EXIT_FAILURE); } /* 遍历 fd_set 扫描所有的文件描述符*/ for (fd = 0; fd < (int)testfds.fd_count; fd++) { if (testfds.fd_array[fd] == server_sockfd) { /*找到相关文件描述符*/ if (FD_ISSET(testfds.fd_array[fd], &testfds)) //有新的连接 { client_len = sizeof(client_address); client_sockfd = accept(server_sockfd, (struct sockaddr *) &client_address, &client_len); FD_SET(client_sockfd, &readfds);//将客户端socket加入到集合中 char ipBuf[20] = { 0 };// inet_ntop(AF_INET, (void*)&client_address.sin_addr, ipBuf, 16); inet_ntoa(client_address.sin_addr);//将sin_addr储存的IP(数值)转换成字符串形式(127.0.0.1) printf("%s: 新连接%s 到 socket#%d\n", argv[0], inet_ntoa(client_address.sin_addr), client_sockfd); break; } } else { //客户还是服务器应用程序都用recv函数从TCP连接的另一端接收数据 //第一个参数指定接收端套接字描述符 if (recv(testfds.fd_array[fd], buf, BUFF_LEN - 1, 0) > 0) { printf("buf = %s\n", buf); for (j = 0; j < (int)readfds.fd_count; j++) { if ((readfds.fd_array[j] != testfds.fd_array[fd]) && (readfds.fd_array[j] != server_sockfd)) //不发送给自己 send(readfds.fd_array[j], buf, sizeof(buf), 0); } } } } } closesocket(server_sockfd); //释放winsock库 WSACleanup(); return 0;}
0 0
- Socket实现聊天发文件
- android socket 聊天实现
- socket 实现多线程聊天
- Socket实现聊天客户端
- Socket实现聊天功能
- Socket 实现聊天功能
- java socket聊天室 swing做界面 Tcp为通讯协议 支持私聊 群聊 发文件
- socket实现WP7即时聊天
- C# Socket实现聊天通信
- android socket nio 聊天实现
- socket.io 实现网页聊天
- 使用Socket实现简单聊天
- java Socket简单聊天实现
- socket之聊天功能实现
- Java网络----Socket, 多线程实现内网多人聊天及一对一聊天
- .Net socket实现简单的聊天
- 用Socket实现聊天小程序
- 利用socket实现简易聊天程序
- lucene6按照整形数据排序搜索结果
- Codeforces Round #404 (Div. 2) B题
- (二)jmeter beanShell jar调用
- 数据库-数据库、基本表、视图的创建,触发器的使用
- struts2标签的使用
- Socket实现聊天发文件
- CF
- python 各种包下载大全网址
- 整数排序
- 南京拓界笔试+一面
- 紫书动规 例题9-10 UVA
- OpenGL纹理详解(下)
- Android USB通讯(完整版)
- 线性时间的最大子数组