#include <unistd.h>
#include <netinet/in.h>
#include <pthread.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#define MAXSIZE 1024 //buf maximum length
#define MAXLINE 1000 //can send a message maximum length
#define TYPEBUF 1 //message types buf length
#define MINNAME 3
#define MAXNAME (MAXSIZE - MAXLINE - TYPEBUF -1 -2) //subtracting one '\n' character, two ':' characters
/* for message type */
#define LOGIN 'L'
#define SEND 'S'
#define ERROR 'E'
#define NODEF '-'
#define DEFPS "cmd> " //default Prompt string
#define EVFS ":;,/\\'\"[]{}~!@#$%^&*()" //名字中的非法字符集
#define SHOWS(s) do{\
printf("%s", s);\
fflush(stdout);\
} while (0)
char *
jump_chars(char* pm, const char* s)
{
const char *ps;
for (; *pm; ++pm) {
for (ps = s; *ps; ps++) {
if (*pm == *ps) break;
}
if (!*ps) break;
}
if (*pm) return(pm);
return(0);
}
char *
tail_del_chars(char* pm, const char* s)
{
const char *ps;
char *p = pm;
p += strlen(pm);
for (--p; p != pm; --p) {
for (ps = s; *ps; ps++) {
if (*p == *ps) break;
}
if (!*ps) break;
}
if (p != pm) {
p[1] = '\0';
return(pm);
}
return(0);
}
void
del_n(char *p, int l)
{
int len = l;
if (l == 0) {
len = strlen(p);
}
if (p[len-1] == '\n') {
p[len-1] = '\0';
}
}
/* 对数据的简单分解,返回0指示了消息格式的不正确 */
void *
msg_fj(char* pm, char **pptype, char** ppname, char** ppmsg)
{
int n;
char *p = pm;
*pptype = pm;
n = strcspn(pm, ":");
if (n == strlen(pm)) {
goto _err_quit;
}
pm += n;
*pm = 0;
pm++;
*ppname = pm;
n = strcspn(pm, ":");
if (n == strlen(pm)) {
goto _err_quit;
}
pm += n;
*pm = 0;
pm++;
*ppmsg = pm;
return(p);
_err_quit:
*pptype = 0;
*ppname = 0;
*ppmsg = 0;
return(0);
}
int
main(int argc, char *argv[])
{
struct sockaddr_in server_addr;
int n, port, sockfd, slctret;
char c, *p, *pcmd, *pr;
fd_set r_set;
char buf[MAXSIZE], line[MAXLINE];
char logname[MAXNAME], toname[MAXNAME], type;
char ps[256];
char *ptype, *pname, *pmsg;
int len;
if (argc != 3) {
fprintf(stderr, "usage: %s <Ip address> <Port number>\n", argv[0]);
exit(1);
}
if (inet_pton(AF_INET, argv[1], &server_addr.sin_addr.s_addr) != 1) {
fprintf(stderr,"%s: %s: IP Address error\n", argv[0], argv[1]);
exit(1);
}
c = 0;
for (p = argv[2];*p != '\0'; p++) {
if (*p > '9' || *p < '0') {
c = 1;
break;
}
}
if ((port = atoi(argv[2])) <= 0 || c) {
fprintf(stderr,"%s: %s: Port number error\n", argv[0], argv[2]);
exit(1);
}
server_addr.sin_port = htons(port);
server_addr.sin_family = AF_INET;
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
fprintf(stderr, "%s: socket error: %s\n", argv[0], strerror(errno));
exit(1);
}
if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
fprintf(stderr, "%s: connect error: %s\n", argv[0], strerror(errno));
exit(1);
}
/* set login name */
for (;;) {
printf("Login: ");
fflush(stdout);
memset(line, 0, sizeof(line));
fgets(line, MAXLINE, stdin);
if (strlen(line) == 0) {
printf("\n");
continue;
}
p = jump_chars(line, " \t");
len = strlen(p);
del_n(p, len);
len = strlen(p);
n = strcspn(p, EVFS);
if (n < len) {
printf("Login: error: User name contains the forbidden character\n");
continue;
}
if (len > MAXNAME-1 || len < MINNAME) {
printf("Login: error: User name too long or is too short, "
"because should between %d-%d\n", MINNAME, MAXNAME-1);
continue;
}
memset(logname, 0, sizeof(logname));
strncpy(logname, p, len);
break;
}
/* login to server */
type = LOGIN;
n = snprintf(buf, sizeof(buf), "%c:%s:", type, logname);
if (write(sockfd, buf, n) != n) {
fprintf(stderr, "%s: error: server closed\n", argv[0]);
exit(1);
}
if ((n = read(sockfd, buf, sizeof(buf))) <= 0) {
fprintf(stderr, "%s: error: server closed\n", argv[0]);
exit(1);
}
if (msg_fj(buf, &ptype, &pname, &pmsg) == 0) {
printf("%s: error: server exceprion datas\n", argv[0]);
exit(1);
}
if (*ptype == ERROR && *pname == '\0') {
printf("%s: error: %s\n", argv[0], pmsg);
exit(2);
} else if (*ptype == ERROR && *pname != '\0') {
printf("%s: error: %s exists\n", argv[0], logname);
exit(1);
} else if (*ptype == LOGIN) {
printf("%s login success\n", logname);
} else {
printf("%s: error: server exceprion datas\n", argv[0]);
write(1, buf, n);
exit(1);
}
memset(toname, 0, sizeof(toname));
memset(ps, 0, sizeof(ps));
strcpy(ps, "cmd> ");
type = NODEF;
for (;;) {
SHOWS(ps);
FD_ZERO(&r_set);
FD_SET(STDIN_FILENO, &r_set);
FD_SET(sockfd, &r_set);
slctret = select(sockfd+1, &r_set, 0, 0, 0);
if (slctret < 0) {
fprintf(stderr, "%s: select error: %s\n", argv[0], strerror(errno));
exit(2);
}
memset(buf, 0, sizeof(buf));
if (FD_ISSET(STDIN_FILENO, &r_set)) {
memset(line, 0, sizeof(line));
if ((n = read(STDIN_FILENO, line, MAXLINE)) < 0) {
fprintf(stderr, "%s: read error: %s\n", argv[0], strerror(errno));
close(sockfd);
exit(1);
} else if (n == 0) {
write(1, "\nclose client\n", strlen("\nclose client\n"));
close(sockfd);
exit(0);
}
if (line[0] == '\n') {
continue;
}
p = jump_chars(line, " \t");
del_n(line, 0);
tail_del_chars(p, " \t");
if (!strcmp(p, "!quit") || !strcmp(p, "!exit") || !strcmp(p, "!logout")) {
printf("logout\n");
exit(0);
} else if (strstr(p, "!to") == p) {
pcmd = p;
p += 2;
if (*p == '\0') {
printf("no parament\n");
continue;
}
*p = '\0';
p++;
p = jump_chars(p , "\t ");
if (p == 0) {
printf("command expr error\n");
continue;
}
pr = p;
n = strlen(pr);
if (n > MAXNAME-1 || n < MINNAME) {
printf("%s: name too lang or too laa\n", pr);
continue;
}
if (strcspn(pr, EVFS) != n) {
printf("%s: exception user name\n", pr);
continue;
}
type = SEND;
strcpy(toname, pr);
snprintf(ps, sizeof(ps), "send to %s> ", toname);
continue;
}
if (type == NODEF) {
printf("what are you doing\n");
continue;
}
if (toname[0] && type == SEND) {
n = snprintf(buf, MAXSIZE, "%c:%s:%s", type, toname, line);
/* send to server */
if (write(sockfd, buf, n) != n) {
fprintf(stderr, "%s: send error: %s\n", argv[0], strerror(errno));
printf("%s: connect refused\n", argv[0]);
exit(1);
}
continue;
}
printf("error: command not found\n");
continue;
}
if (FD_ISSET(sockfd, &r_set)) {
if ((n = read(sockfd, buf, MAXSIZE)) < 0) {
fprintf(stderr, "%s: read error: %s\n", argv[0], strerror(errno));
exit(1);
} else if (n == 0) {
printf("\nserver closed, connect refused\n");
exit(0);
}
if (msg_fj(buf, &ptype, &pname, &pmsg) == 0) {
printf("%s: warning: receiving exception datas\n", argv[0]);
/* 忽略 */
continue;
}
switch (*ptype) {
case SEND:
printf("%s: %s\n", pname, pmsg);
break;
case ERROR:
printf("Server message: %s\n", pmsg);
if (strcmp(pname, toname) == 0) {
strcpy(ps, DEFPS);
memset(toname, 0, sizeof(toname));
type = NODEF;
}
break;
default:
printf("%s: error: exception datas\n", argv[0]);
exit(2);
}
}
}
exit(0);
}
/* main end */
|