服务端做数据处理:每一个用户是一个客服端,每一个用户上线服务端记录。每个用户的发言都会被服务端通知到其它给用户。
Makefile
all: server client
server: chat_room.c
gcc chat_room.c -o server -g -DDEBUG
client: client.c
gcc client.c -o client -g
clean:
rm server client
.PHONY: clean
usr_info.txt
Teach.Zhang
Teach.Gao
Teach.Wu
/* client.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/mman.h>
#define SERV_PORT 8000
#define SERV_IP "127.0.0.1"
int main(int argc, char *argv[])
{
char *usr_name;
int sfd, n, i;
struct sockaddr_in serv_addr;
char buf[1024];
pid_t *pid, tpid;
usr_name = argv[1];
sfd = socket(AF_INET, SOCK_DGRAM, 0);
if(sfd == -1)
return -1;
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(SERV_PORT);
inet_pton(AF_INET, SERV_IP, &serv_addr.sin_addr.s_addr);
sprintf(buf, "syn %s", usr_name);
n = sendto(sfd, buf, strlen(buf), 0,
(struct sockaddr *)&serv_addr, sizeof(serv_addr));
n = recvfrom(sfd, buf, 1024, 0, NULL, NULL);
buf[n] = '\0';
if(strcmp(buf, "OK")){
printf("fail to login...\n");
return 0;
}
pid = (pid_t *)mmap(NULL, sizeof(pid) * 2, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
for(i = 0; i < 2; i++){
if((tpid = fork()) == 0)
break;
pid[i] = tpid;
}
if(i == 0){
while(1){
n = read(STDIN_FILENO, buf, 1024);
if(buf[0] == '#')
break;
n = sendto(sfd, buf, n, 0,
(struct sockaddr *)&serv_addr,
sizeof(serv_addr));
}
kill(pid[1], SIGUSR1);
return 0;
}else if(i == 1){
while(1){
n = recvfrom(sfd, buf, 1024, 0, NULL, NULL);
write(STDOUT_FILENO, buf, n);
}
return 0;
}else
for(i = 0; i < 2; i++)
wait(NULL);
tryagain:
sprintf(buf, "fin %s", usr_name);
n = sendto(sfd, buf, strlen(buf), 0,
(struct sockaddr *)&serv_addr, sizeof(serv_addr));
n = recvfrom(sfd, buf, 1024, 0, NULL, NULL);
buf[n] = '\0';
if(strcmp(buf, "OK")){
sleep(1);
printf("fail to logout...\n");
goto tryagain;
}
close(sfd);
return 0;
}
/* chat_room.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
typedef struct usr
{
char *usr_name;
struct sockaddr_in addr;
int is_online;
struct usr *next;
}usr_t;
usr_t *head = NULL;
usr_t *new_node(const char *usr_name)
{
usr_t *p;
p = (usr_t *)malloc(sizeof(usr_t));
if(p == NULL)
return NULL;
p->usr_name = (char *)malloc(sizeof(char) * (strlen(usr_name) + 1));
strcpy(p->usr_name, usr_name);
p->is_online = 0;
p->next = NULL;
memset(&p->addr, 0, sizeof(p->addr));
return p;
}
int insert(const char *usr_name)
{
usr_t *p, *q;
p = new_node(usr_name);
if(p == NULL)
return -1;
if(head == NULL){
head = p;
return 0;
}
for(q = head; q->next != NULL; q = q->next);
q->next = p;
return 0;
}
int is_equal(struct sockaddr_in *p, struct sockaddr_in *q)
{
return p->sin_family == q->sin_family && p->sin_port == q->sin_port && p->sin_addr.s_addr == q->sin_addr.s_addr;
}
usr_t *search_by_addr(struct sockaddr_in *addr)
{
usr_t *p;
for(p = head; p != NULL; p = p->next)
if(is_equal(&p->addr, addr))
return p;
return NULL;
}
usr_t *search_by_name(const char *usr_name)
{
usr_t *p;
for(p = head; p != NULL; p = p->next)
if(strcmp(p->usr_name, usr_name) == 0)
break;
return p;
}
void print(void)
{
usr_t *p;
char ip[20];
for(p = head; p != NULL; p = p->next){
printf("name : %s, ", p->usr_name);
if(p->is_online == 0)
printf("out-of-line, ");
else
printf("online, ");
inet_ntop(AF_INET, &p->addr.sin_addr.s_addr, ip, 20);
printf("ip : %s, ", ip);
printf("port : %u\n", ntohs(p->addr.sin_port));
}
}
void destroy(void)
{
usr_t *p, *q;
for(p = head; p != NULL; p = q){
q = p->next;
free(p->usr_name);
free(p);
}
head = NULL;
}
int get_usr_info(const char *filename)
{
FILE *fp;
char buf[1024];
fp = fopen(filename, "r");
if(fp == NULL)
return -1;
while(fgets(buf, 1024, fp)){
buf[strlen(buf) - 1] = '\0';
insert(buf);
}
fclose(fp);
return 0;
}
int sock_init(in_port_t port, const char *ip)
{
int sfd;
struct sockaddr_in serv_addr;
sfd = socket(AF_INET, SOCK_DGRAM, 0);
if(sfd == -1)
return -1;
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(port);
inet_pton(AF_INET, ip, &serv_addr.sin_addr.s_addr);
if(bind(sfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1)
return -1;
return sfd;
}
int main(void)
{
int sfd, n;
char buf[1024];
usr_t *p; socklen_t len;
struct sockaddr_in cli_addr;
get_usr_info("usr_info.txt");
sfd = sock_init(8000, "127.0.0.1");
while(1){
len = sizeof(struct sockaddr_in);
n = recvfrom(sfd, buf, 1024, 0,
(struct sockaddr *)&cli_addr, &len);
buf[n] = '\0';
if(strncmp(buf, "syn", 3) == 0){ /* login */
char *name;
name = strstr(buf, " ");
name++;
p = search_by_name(name);
if(p == NULL)
sendto(sfd, "fail", strlen("fail"), 0,
(struct sockaddr *)&cli_addr, sizeof(cli_addr));
else{
p->is_online = 1;
p->addr = cli_addr;
sendto(sfd, "OK", strlen("OK"), 0,
(struct sockaddr *)&cli_addr, sizeof(cli_addr));
}
#ifdef DEBUG
print();
#endif
}else if(strncmp(buf, "fin", 3) == 0){ /* logout */
char *name;
name = strstr(buf, " ");
name++;
p = search_by_name(name);
if(p == NULL)
sendto(sfd, "fail", strlen("fail"), 0,
(struct sockaddr *)&cli_addr, sizeof(cli_addr));
else{
p->is_online = 0;
memset(&p->addr, 0, sizeof(p->addr));
sendto(sfd, "OK", strlen("OK"), 0,
(struct sockaddr *)&cli_addr, sizeof(cli_addr));
}
#ifdef DEBUG
print();
#endif
}else{ /* somebody talk */
char msg[32];
p = search_by_addr(&cli_addr);
if(p == NULL)
continue;
sprintf(msg, "%s say : ", p->usr_name);
for(p = head; p != NULL; p = p->next){
if(p->is_online){
n = sendto(sfd, msg, strlen(msg), 0,
(struct sockaddr *)&p->addr, sizeof(p->addr));
n = sendto(sfd, buf, strlen(buf), 0,
(struct sockaddr *)&p->addr, sizeof(p->addr));
}
}
}
printf("one data over...\n");
}
destroy();
return 0;
}
//linux
Makefile
all: server client
server: server.c
gcc server.c -o server -g
client: client.c
gcc client.c -o client -g
clean:
rm server client
.PHONY: clean
/* 一个客户端、服务器程序
客户端发送数据给服务端,服务端数据进行转换,然后发送给客户端。
//client.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define SERV_IP "192.168.175.128"
#define SERV_PORT 8000
int main(void){
int sfd, n;
struct sockaddr_in serv_addr;
char buf[1024];
sfd = socket(AF_INET, SOCK_STREAM, 0);
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(SERV_PORT);
inet_pton(AF_INET, SERV_IP, &serv_addr.sin_addr.s_addr);
n = connect(sfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
while(1){
n = read(STDIN_FILENO, buf, 1024);
if(n == 0)
break;
write(sfd, buf, n);
n = read(sfd, buf, 1024);
write(STDOUT_FILENO, buf, n);
}
close(sfd);
return 0;
}
//server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define SERV_IP "192.168.175.128"
#define SERV_PORT 8000
void err_sys(const char *str){
perror(str);
exit(1);
}
int main(void){
int lfd;
struct sockaddr_in serv_addr;
int n;
lfd = socket(AF_INET, SOCK_STREAM, 0);
if(lfd == -1)
err_sys("socket error");
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(SERV_PORT);
inet_pton(AF_INET, SERV_IP, &serv_addr.sin_addr.s_addr);
n = bind(lfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
if(n == -1)
err_sys("bind error");
n = listen(lfd, 20);
if(n == -1)
err_sys("listen error");
//pause();
while(1){
int cfd, i;
char buf[1024];
cfd = accept(lfd, NULL, NULL);
if(cfd == -1)
err_sys("accept error");
while(1){
n = read(cfd, buf, 1024);
if(n == 0){
printf("connection closed...\n");
break;
}
for(i = 0; i < n; i++)
buf[i] = toupper(buf[i]);
write(cfd, buf, n);
write(STDOUT_FILENO, buf, n);
}
close(cfd);
}
printf("should not be here\n");
return 0;
}
/* windows client */
//client.c
#include<winsock2.h>
#include<iostream>
#include<string>
using namespace std;
#pragma comment(lib, "ws2_32.lib")
int main(){
WORD sockVersion = MAKEWORD(2, 2);
WSADATA data;
if (WSAStartup(sockVersion, &data) != 0)
return 1;
while (true){
SOCKET clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (clientSocket == INVALID_SOCKET){
return 1;
}
sockaddr_in sock_in;
sock_in.sin_family = AF_INET;
sock_in.sin_port = htons(8888);
sock_in.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
if (connect(clientSocket, (sockaddr*)&sock_in, sizeof(sock_in)) == SOCKET_ERROR){
return 1;
}
string data;
getline(cin, data);
const char * msg;
msg = data.c_str();
send(clientSocket, msg, strlen(msg), 0);
char revdata[100];
int num = recv(clientSocket, revdata, 100, 0);
if (num > 0){
revdata[num] = '\0';
cout << "Sever say:" << revdata << endl;
}
closesocket(clientSocket);
}
WSACleanup();
return 0;
}
//server.c win server
#include<winsock2.h>
#include<iostream>
#include<string>
using namespace std;
#pragma comment(lib,"ws2_32.lib") //表示链接wpcap.lib这个库。和在工程设置里写上链入wpcap.lib的效果一样
int main(int argc, char* argv[]){
//初始化DLL
WORD sockVersion = MAKEWORD(2, 2); //表示使用WINSOCK2版本
WSADATA wsdata; //用来存储系统传回的关于WINSOCK的资料
if (WSAStartup(sockVersion, &wsdata) != 0) //连接应用程序与winsock.dll的第一个调用
return 1;
//创建套接字
SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (serverSocket == INVALID_SOCKET)
return 1;
//绑定套接字
sockaddr_in sockAddr;
sockAddr.sin_family = AF_INET;
sockAddr.sin_port = htons(8888);
sockAddr.sin_addr.S_un.S_addr = INADDR_ANY;
if (bind(serverSocket, (sockaddr*)&sockAddr, sizeof(sockAddr)) == SOCKET_ERROR)
return 1;
//开始监听
if (listen(serverSocket, 10) == SOCKET_ERROR)
return 1;
SOCKET clientSocket;
sockaddr_in client_sin;
char msg[100];//存储传送的消息
int flag = 0;//是否已经连接上
int len = sizeof(client_sin);
while (true){
if (!flag)
cout << "等待连接..." << endl;
clientSocket = accept(serverSocket, (sockaddr*)&client_sin, &len);
if (clientSocket == INVALID_SOCKET){
flag = 0;
return 1;
}
if (!flag)
cout << "接收到一个链接:" << inet_ntoa(client_sin.sin_addr) << endl;
flag = 1;
int num = recv(clientSocket, msg, 100, 0);
if (num > 0){
msg[num] = '\0';
cout << "Client say: " << msg << endl;
}
string data;
getline(cin, data);
const char * sendData;
sendData = data.c_str();
send(clientSocket, sendData, strlen(sendData), 0);
closesocket(clientSocket);
}
closesocket(serverSocket);
WSACleanup();
return 0;
}