本篇主要为客户端相应功能的实现.
由于服务端只提供其他客户端的IP及端口号,而客户端同客户端之间的通信是不通过服务端的,所以每个客户端又分为两个部分,一是客户端中的客户端,二是客户端中的服务端.
客户端供用户来连接其他客户端的服务端或者总的服务端,而客户端中的服务端供其他客户端来连接,所以实现方法类似于上一篇中的服务端.
这样的话,客户端的socket就出现了一个问题,当时被这个问题困扰了好久.
由于客户端需要socket去进行connect,同时还需要其进行listen,本来只以为用一个socket就可以了,后来问了许多大神,查了一些资料,才对socket了有更深的理解.
一个socket是不能同时进行listen和connect的,所以在客户端中,需要用到两个socket,一个负责connect到总服务端,另一个为自身服务端listen用,以接收其他客户端的connect.
以下是客户端中的服务端相应功能的实现:
#include "chatSys.h"
/*****************
作用: 负责连接服务器,向服务器发送所绑定的端口号,
同时作为客户端中的服务端,处理其他客户端的接入请求
参数: pPresentInfo.localPort 将要绑定的本地端口号, pPresentInfo.tagserverIP 服务器IP, pPresentInfo.tagserverPort 服务器端口号
返回值: 无
作者: llh 日期:2016/9/14
******************/
void clientSelfServer(void* pPresentInfo)
{
SelfBindPortAndTagInfo presentInfo = *(SelfBindPortAndTagInfo *)pPresentInfo;
/*
*为了让其它客户端能和本客户端进行通信,所以将本地端口发送给服务器
*服务器中维护一张所以在线客户端的端口和IP地址表
*/
//连接socket
int sendServerSocket = socket(AF_INET,SOCK_STREAM, 0);
int localServerSocket = socket(AF_INET,SOCK_STREAM, 0);
//异常处理
if(SOCKET_CREATE_FAILURE == sendServerSocket || SOCKET_CREATE_FAILURE == localServerSocket)
{
printf("\n\r socket create failure!!!");
return;
}
//连接服务器
SocketAddress serverSocketIn;
memset(&serverSocketIn, 0, sizeof(serverSocketIn));
serverSocketIn.sin_family = AF_INET;
serverSocketIn.sin_port = htons(presentInfo.tagserverPort); ///服务器端口
serverSocketIn.sin_addr.s_addr = inet_addr(presentInfo.tagserverIP); ///服务器ip
if(CONNECT_FAILURE == sendOnlineInfo(sendServerSocket, &serverSocketIn))
printf("\n\r connect server failure!!!");
globalSocket = sendServerSocket;
//绑定端口
SocketAddress localServerSockAddr;
localServerSockAddr.sin_family = AF_INET;
localServerSockAddr.sin_port = htons(presentInfo.localPort);//本地服务器端口
localServerSockAddr.sin_addr.s_addr = inet_addr(SERVERIP);
if(ERROR == bind(localServerSocket,(struct sockaddr *)&localServerSockAddr,sizeof(localServerSockAddr)))
{
printf("\n\r bind create failure!!!");
return;
}
//向服务器告知绑定的端口号
char nowPortStr[SHORT_STRING];
memset(nowPortStr, 0, SHORT_STRING * sizeof(char));
sprintf(nowPortStr, "%d", presentInfo.localPort);
//向服务器发送标志,标志为即将发送端口号,等待服务器确认回应
send(sendServerSocket, SENDPORTSIGN, sizeof(SENDPORTSIGN), 0);
char testStr[SHORT_STRING];
memset(testStr, 0, SHORT_STRING * sizeof(char));
recv(sendServerSocket, testStr, SHORT_STRING * sizeof(char), 0);
if(strcmp(testStr, TESTSIGNSUCS) == 0)
send(sendServerSocket, nowPortStr, sizeof(nowPortStr), 0);
//等待连接
if(listen(localServerSocket, QUEUE) == ERROR)
{
perror("listen");
exit(1);
}
//每当一个客户端连接,创建一个新的线程负责处理
int countM = 0;
while(countM < MAXTHREAD)
{
struct conMySocket myConsocket;
socklen_t length = sizeof(myConsocket.clientSocket);
///成功返回非负描述字,出错返回-1
///accept在此处为阻塞函数,提取出所监听套接字的等待连接队列中第一个连接请求
myConsocket.con = accept(localServerSocket, (struct sockaddr*)&(myConsocket.clientSocket), &length);
if(myConsocket.con <= ACCEPT_FAILURE)
{
perror("accept");
exit(1);
}
if(pthread_create(&threadId[countM], NULL, (void *)singleThrd, &myConsocket))
{
printf ("Create pthread error!\n");
exit(1);
}
countM++;
}
close(localServerSocket);
return;
}
/**********************************
*作用:向服务器发送在线消息,如果未收到
服务器应对信息,则判断连接失败服务器
*参数
*作者:cl 日期:2016.9.12
***********************************/
int sendOnlineInfo(int sendServerSocket, SocketAddress* mySocketAddress)
{
int count = 0;
while(connect(sendServerSocket, (struct sockaddr *)mySocketAddress, sizeof(*mySocketAddress)) < 0)
{
if(100 == count)
{
return CONNECT_FAILURE;
}
sleep(0.1);
count++;
}
//设置recv等待最大时长为3秒
struct timeval timeout={MAX_TIMEWATI,0};
//设置该socket的recv等待
setsockopt(sendServerSocket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(timeout));
//向服务器发送检测标志,等待回复
send(sendServerSocket, TESTSIGN, sizeof(TESTSIGN), 0);
char teststr[SHORT_STRING];
memset(teststr, 0, SHORT_STRING * sizeof(char));
int recvsign = recv(sendServerSocket, teststr, SHORT_STRING * sizeof(char), 0);
//若recv在设定时间MAX_TIMEWATI内未等待到回复,则判断为连接服务器超时
if(recvsign == -1)
{
printf("timeout\n");
return CONNECT_FAILURE;
}
else if(strcmp(teststr, TESTSIGNSUCS) == 0)
return CONNECT_SUCCESS;
else
return CONNECT_FAILURE;
}
/**********************************
*作用:同其他用户进行聊天,发送并接受对方消息
*参数:requestSocket目标socket描述
*作者:llh 日期:2016.9.19
***********************************/
void chatWithOtherUser(int requestSocket)
{
send(requestSocket, TESTSIGNSUCS, sizeof(TESTSIGNSUCS), 0);
char buffer[BUFFER_SIZE];
while(1)
{
memset(buffer,0,sizeof(buffer));
int len = recv(requestSocket, buffer, sizeof(buffer),0);
//需要退出时输入exit并发送,同时服务端也会收到此消息进行退出聊天操作
if(strcmp(buffer,"exit\n")==0)
break;
fputs(buffer, stdout);
send(requestSocket, buffer, len, 0);
}
close(requestSocket);
}
/**********************************
*作用:接收文件,拼接已有路径存储想要接收的文件
*参数:requestSocket目标socket描述
*作者:llh 日期:2016.9.19
***********************************/
int recvFile(int requestSocket)
{
char filePath[MAXINFOSTRLENGTH], fileName[MAXINFOSTRLENGTH];
memset(filePath, 0, MAXINFOSTRLENGTH * sizeof(char));
strcpy(filePath, NOWPATH);
memset(fileName, 0, MAXINFOSTRLENGTH * sizeof(char));
//向另一端发送确定标志,已准备好接收文件名等信息
send(requestSocket, TESTSIGNSUCS, sizeof(TESTSIGNSUCS), 0);
//接收文件名
recv(requestSocket, fileName, MAXINFOSTRLENGTH * sizeof(char), 0);
//把当前临时地址与文件名拼接
strcat(filePath, fileName);
strcpy(fileName, filePath);
FILE *wfp = fopen(fileName, "wb");
unsigned char buffer[BUFFER_SIZE];
memset(buffer, 0, BUFFER_SIZE * sizeof(unsigned char));
if(NULL == wfp)
{
printf("file:\t%s can not open or create\n", fileName);
return 0;
}
int length = 0;
while((length = recv(requestSocket, buffer, BUFFER_SIZE * sizeof(unsigned char), 0)) > 0)
{
fwrite(buffer, sizeof(unsigned char), length, wfp);
//清除读写缓冲区,需要立即把输出缓冲区的数据进行物理写入时
fflush(wfp);
}
fclose(wfp);
return 1;
}
/*****************
作用: 单个线程的进入函数,
根据另一客户端的发送信号,
可进行聊天或文件传送
参数: recvClientSockct为已连接的另一客户端socket描述
返回值: 无
作者: llh
******************/
void singleThrd(void *recvClientSockct)
{
struct conMySocket myConsocket = *((struct conMySocket *)recvClientSockct);
while(1)
{
char buffer[BUFFER_SIZE];
memset(buffer, 0, BUFFER_SIZE * sizeof(char));
recv(myConsocket.con, buffer, BUFFER_SIZE * sizeof(char), 0);
//验证反馈
if(strcmp(buffer, TESTSIGN) == 0)
{
send(myConsocket.con, TESTSIGNSUCS, sizeof(TESTSIGNSUCS), 0);
continue;
}
//收到发送文件标志,则调用接收文件函数进行接收
if(strcmp(buffer, SENDFILEREQUEST) == 0)
{
recvFile(myConsocket.con);
continue;
}
//收到聊天标志,调用聊天函数进行聊天
if(strcmp(buffer, CHATSIGN) == 0)
{
chatWithOtherUser(myConsocket.con);
continue;
}
}
close(myConsocket.con);
return;
}
这里提一个细节,在实现写文件功能的时候,每次发送来的最后一个字符串总是写入不进去,起初以为发送的字符串有问题,但是后来把发送的字符串都打印测试了一遍,发现发送和接收的字符串都没有问题,被这个东西困扰了好久好久,在问了几个大神之后,才得知可以用fflush解决,但是目前还是不清楚为什么总是存在最后一个字符串写入不进去,不论发送的文件多大,总是最后一个字符串无法写入.这里只能是得到了解决方法,至于问题的原因其实还是没有解决.如果有大神看到本篇文章,希望可以解惑一下,谢谢^ ^
接下来是用户操作界面的一些实现,其实也不是纯粹的操作界面,里面也有一部分就是客户端的功能了:
#include "chatSys.h"
/****************
本文件包含各界面函数的实现以及控制界面显示流程的总控制函数的实现
作者:llh 日期:2016/9/14
****************/
/*****************
作用: 绑定本地端口作服务端端口供其他客户端连接
参数: 无
作者: llh 日期:2016/9/19
******************/
int bindPortInterface()
{
int localPort = 0;
printf("Please input local port:");
scanf("%d", &localPort);
return localPort;
}
/*****************
作用: 显示登陆界面
参数: 无
作者: llh 日期:2016/9/19
******************/
int loginInterface()
{
int choiceNum = 0;
system("clear");
printf(" MyTestChatting\n");
printf("1.login\t 2.exit\n");
printf("Please choose:");
scanf("%d", &choiceNum);
return choiceNum;
}
/*****************
作用: 显示输入账户密码界面
参数: *account,*password为字符串指针,输入的账户密码存入此指针指向的内存空间
作者: llh 日期:2016/9/19
******************/
void inputAccountPasswordInterface(char *account, char *password)
{
printf("Please input account and password:");
scanf("%s %s", account, password);
}
/*****************
作用: 将账户密码发送至服务端进行验证并返回验证结果
参数: *account,*password为账户密码字符串指针,tagSocket为目标socket描述
作者: llh 日期:2016/9/19
******************/
int sendAccountPassword(int tagSocket, char *account, char *password)
{
char teststr[SHORT_STRING];
memset(teststr, 0, SHORT_STRING * sizeof(char));
//向服务器发送核对帐号密码标志,等待服务器返回确认结果
send(tagSocket, CHECKSIGN, sizeof(CHECKSIGN), 0);
recv(tagSocket, teststr, SHORT_STRING * sizeof(char), 0);
if(strcmp(teststr, TESTSIGNSUCS) == 0)
{
//若服务器确认已准备好接收帐号密码,则进行帐号密码的两次连续发送
char checkResult[SHORT_STRING];
memset(checkResult, 0, SHORT_STRING * sizeof(char));
send(tagSocket, account, SHORT_STRING * sizeof(char), 0);
send(tagSocket, password, SHORT_STRING * sizeof(char), 0);
//接收登陆是否成功的结果
recv(tagSocket, checkResult, SHORT_STRING * sizeof(char), 0);
if(strcmp(checkResult, LOGINSUCCESSRET) == 0)
return LOGINSUCCESS;
else
return LOGINFAILURE;
}
else
return ERROR;
}
/*****************
作用: 显示当前在线用户ID以供选择
参数: tagSocket为目标socket描述
作者: llh 日期:2016/9/19
******************/
int onLineUserInfo(int tagSocket)
{
//设置无限循环供选择是否继续等待,
//根据选择可再次请求服务器获取最新当前在线用户信息
while(1)
{
char teststr[SHORT_STRING];
memset(teststr, 0, SHORT_STRING * sizeof(char));
//向服务器发送获得当前在线用户信息请求
send(tagSocket, ONLINEUSERINFOREQUEST, sizeof(ONLINEUSERINFOREQUEST), 0);
recv(tagSocket, teststr, SHORT_STRING * sizeof(char), 0);
if(strcmp(teststr, TESTSIGNSUCS) == 0)
{
//若服务器返回标志正确,则等待接收当前在线用户信息显示
char onlineUserInfoStr[MAXINFOSTRLENGTH];
memset(onlineUserInfoStr, 0, MAXINFOSTRLENGTH * sizeof(char));
recv(tagSocket, onlineUserInfoStr, MAXINFOSTRLENGTH * sizeof(char), 0);
//若当前无人在线,则根据选择是否继续等待
if(strcmp(onlineUserInfoStr, NOBODYONLIEN) == 0)
{
printf("nobody online\n");
int whetherWait = 0;
printf("1.wait\t2.exit\n");
printf("Please choose whether wait:");
scanf("%d", &whetherWait);
if(WAITACES == whetherWait)
{
//若选择等待则再次请求服务器获取当前用户在线信息
//sleep(MAX_TIMESLEEPINFO);
continue;
}
else
exit(0);
}
else
{
printf("online usersId:");
printf("%s\n", onlineUserInfoStr);
int choiceId = 0;
printf("Please choose one to chat or sendfile\n");
scanf("%d", &choiceId);
return choiceId;
}
}
else
return ERROR;
}
}
/*****************
作用: 显示选择界面以供用户选择聊天或传送文件
参数: 无
作者: llh 日期:2016/9/19
******************/
int tagFunction()
{
int choicNum = 0;
printf("1.chat\t2.send file\n");
printf("Please choose:");
scanf("%d", &choicNum);
return choicNum;
}
/*****************
作用: 根据用户需求控制各界面执行流程
参数: tagSocket为目标socket描述
作者: llh 日期:2016/9/19
******************/
int controlChoose(int tagSocket)
{
//设定无限循环显示所需界面
while(1)
{
//显示程序初始界面供用户选择是否登陆
int retLoginIn = loginInterface();
if(1 == retLoginIn)
{
//获得用户账户密码信息后发送到服务器进行验证
char userAccount[SHORT_STRING], userPassword[SHORT_STRING];
memset(userAccount, 0, SHORT_STRING * sizeof(char));
memset(userPassword, 0, SHORT_STRING * sizeof(char));
inputAccountPasswordInterface(userAccount, userPassword);
int checkResult = sendAccountPassword(tagSocket, userAccount, userPassword);
if(checkResult == LOGINSUCCESS)
{
while(1)
{
//登陆成功后,请求服务器获取当前在线用户信息
int tagUserId = onLineUserInfo(tagSocket);
if(tagUserId == ERROR)
break;
else
{
int tagUserSocket = connectOtherUser(tagSocket, tagUserId);
if(tagUserSocket != CONNECT_FAILURE)
{
printf("connect success\n");
int tagFunc = tagFunction();
//根据tagFunction函数返回值进行聊天或传送文件操作
if(tagFunc == CHATACES)
{
chatWithTagUser(tagUserSocket);
}
if(tagFunc == SENDFILEACES)
{
sendFile(tagUserSocket);
}
}
else
{
printf("connect failure\n");
}
}
}
}
else if(checkResult == LOGINFAILURE)
{
//登陆失败后,显示结果等待3秒返回初始界面
printf("account or password error\n");
sleep(MAX_TIMESLEEP);
continue;
}
}
else
exit(0);
}
}
方法写的其实挺粗糙的,日后再打磨一下吧...
接下来是客户端的主要功能的实现:
#include "chatSys.h"
/*****************
作用: 向其他客户端的服务端发起连接,通过目标用户ID
从服务器中获得目标用户所在客户端的服务端的IP和其绑定的端口号
参数: tagSocket为已连接的另一客户端socket描述,tagUserId为目标用户ID
作者: llh 日期:2016/9/19
******************/
int connectOtherUser(int tagSocket, int tagUserId)
{
char teststr[SHORT_STRING];
memset(teststr, 0, SHORT_STRING * sizeof(char));
//向目标服务端发送请求连接标志,等待回应
send(tagSocket, OTHERUSERSOCKETREQUEST, sizeof(OTHERUSERSOCKETREQUEST), 0);
recv(tagSocket, teststr, SHORT_STRING * sizeof(char), 0);
//得到正确回应标志后进行目标数据发送接收
if(strcmp(teststr, TESTSIGNSUCS) == 0)
{
char existUser[SHORT_STRING], tagUserIdStr[SHORT_STRING];
char tagUserIP[SHORT_STRING], tagUserPort[SHORT_STRING];
memset(existUser, 0, SHORT_STRING * sizeof(char));
memset(tagUserIdStr, 0, SHORT_STRING * sizeof(char));
memset(tagUserIP, 0, SHORT_STRING * sizeof(char));
memset(tagUserPort, 0, SHORT_STRING * sizeof(char));
sprintf(tagUserIdStr, "%d", tagUserId);
//发送目标用户ID,获得用户是否存在结果,准备从服务器连续目标用户IP地址和端口号
send(tagSocket, tagUserIdStr, SHORT_STRING * sizeof(char), 0);
recv(tagSocket, existUser, SHORT_STRING * sizeof(char), 0);
if(strcmp(existUser, USERNOEXIST) == 0)
return CONNECT_FAILURE;
recv(tagSocket, tagUserIP, SHORT_STRING * sizeof(char), 0);
recv(tagSocket, tagUserPort, SHORT_STRING * sizeof(char), 0);
int withOtherUser = socket(AF_INET,SOCK_STREAM, 0);
//异常处理
if(SOCKET_CREATE_FAILURE == withOtherUser)
{
printf("\n\r socket create failure!!!");
return SOCKET_CREATE_FAILURE;
}
//连接其他客户端的服务端
SocketAddress otherUserSocketIn;
memset(&otherUserSocketIn, 0, sizeof(otherUserSocketIn));
otherUserSocketIn.sin_family = AF_INET;
otherUserSocketIn.sin_port = htons(atoi(tagUserPort)); ///目标客户端服务器端口
otherUserSocketIn.sin_addr.s_addr = inet_addr(tagUserIP); ///目标客户端服务器ip
if(CONNECT_FAILURE == sendOnlineInfo(withOtherUser, &otherUserSocketIn))
return CONNECT_FAILURE;
return withOtherUser;
}
return CONNECT_FAILURE;
}
/*****************
作用: 向其他客户端的服务端发起聊天请求
参数: tagSocket为已连接的另一客户端socket描述
作者: llh 日期:2016/9/19
******************/
void chatWithTagUser(int tagSocket)
{
char sendbuf[BUFFER_SIZE];
char recvbuf[BUFFER_SIZE];
memset(sendbuf, 0, BUFFER_SIZE * sizeof(char));
memset(recvbuf, 0, BUFFER_SIZE * sizeof(char));
//发送聊天标志
send(tagSocket, CHATSIGN, sizeof(CHATSIGN), 0);
recv(tagSocket, recvbuf, BUFFER_SIZE * sizeof(char), 0);
if(strcmp(recvbuf, TESTSIGNSUCS) != 0)
{
close(tagSocket);
return;
}
memset(recvbuf, 0, BUFFER_SIZE * sizeof(char));
//不断接收输入
while (fgets(sendbuf, sizeof(sendbuf), stdin) != NULL)
{
send(tagSocket, sendbuf, strlen(sendbuf),0);
if(strcmp(sendbuf,"exit\n")==0)
break;
recv(tagSocket, recvbuf, sizeof(recvbuf),0);
fputs(recvbuf, stdout);
memset(sendbuf, 0, sizeof(sendbuf));
memset(recvbuf, 0, sizeof(recvbuf));
}
close(tagSocket);
}
/*****************
作用: 向其他客户端的服务端发起发送文件请求
参数: tagSocket为已连接的另一客户端socket描述
作者: llh 日期:2016/9/19
******************/
int sendFile(int tagSocket)
{
char teststr[SHORT_STRING];
memset(teststr, 0, SHORT_STRING * sizeof(char));
//向另一端发送传送文件请求标志,等待回应标志
send(tagSocket, SENDFILEREQUEST, sizeof(SENDFILEREQUEST), 0);
recv(tagSocket, teststr, SHORT_STRING * sizeof(char), 0);
if(strcmp(teststr, TESTSIGNSUCS) == 0)
{
//标志正确,输入文件名以二进制打开
char fileName[MAXINFOSTRLENGTH];
memset(fileName, 0, MAXINFOSTRLENGTH * sizeof(char));
printf("Please input filename:");
scanf("%s", fileName);
FILE *fp = fopen(fileName, "rb");
//若不能正确打开文件,则直接返回
if(NULL == fp)
{
printf("file:\t%s can not open\n", fileName);
return 0;
}
//发送文件名
send(tagSocket, fileName, sizeof(fileName),0);
int length = 0;
unsigned char buffer[BUFFER_SIZE];
memset(buffer, 0, BUFFER_SIZE * sizeof(unsigned char));
//判断只有在文件读出字符数大于0时循环
while((length = fread(buffer, sizeof(unsigned char), BUFFER_SIZE, fp)) > 0)
{
//若发送字符数小于0则直接返回
if(send(tagSocket, buffer, length, 0) < 0)
{
printf("send file:%s failed\n", fileName);
return 0;
}
memset(buffer, 0, BUFFER_SIZE * sizeof(unsigned char));
}
fclose(fp);
}
}
大部分功能都实现的差不多了,头文件里是一些宏的定义,函数声明之类的,也贴一下吧
#ifndef MA
#define MA M
#define SERVERPORT 8080
#define SERVERIP "127.0.0.1"
#define CHECKSIGN "checksign"
#define SENDPORTSIGN "sendportsign"
#define CHATSIGN "chatsign"
#define ONLINEUSERINFOREQUEST "onlineuserinforequest"
#define OTHERUSERSOCKETREQUEST "otherusersocketrequest"
#define SENDFILEREQUEST "sendfilerequest"
#define TESTSIGN "testsign"
#define TESTSIGNSUCS "testsignsuccess"
#define LOGINSUCCESSRET "loginsucess"
#define LOGINFAILURERET "loginfailure"
#define CLIENTCONNECTSIGN "client request"
#define SERVERCONNECTSIGN "server responses"
#define NOBODYONLIEN "nobodyonline"
#define USEREXIST "userexist"
#define USERNOEXIST "usernoexist"
#define STARTPORT 8000
#define QUEUE 20
#define BUFFER_SIZE 1024
#define MAXTHREAD 20
#define MAXPORTCOUNT 100
#define MAXINFOSTRLENGTH 100
#define MAXFILENAMEPATHLENTH 100
#define NOWPATH "/mnt/hgfs/linuxuse/chat/client/recvfileuse/"
#define WAITACES 1
#define CHATACES 1
#define SENDFILEACES 2
#define LOGINSIGN 1
#define LOGINSUCCESS 1
#define LOGINFAILURE 0
#define ERROR -1
#define SOCKET_CREATE_FAILURE -1
#define ACCEPT_FAILURE -1
#define CONNECT_FAILURE -1
#define GLOBALSOCKETINI -1
#define CONNECT_SUCCESS 1
//MAX_TIMEWATI单位为秒
#define MAX_TIMEWATI 3
//MAX_TIMESLEEP单位为毫秒
#define MAX_TIMESLEEP 3
#define MAX_TIMESLEEPINFO 100000
#define SHORT_STRING 20
#endif
#ifndef SYS
#define SYS S
#include "chatMacro.h"
#include "sys/socket.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <sys/time.h>
#include <unistd.h>
#include <pthread.h>
int globalSocket;
pthread_t threadId[MAXTHREAD];
pthread_t mainControlThd;
struct user_info
{
int id_num;//作唯一用户索引
char user_account[SHORT_STRING];//用户帐号
char user_password[SHORT_STRING];//用户密码
char user_nickname[SHORT_STRING];//用户昵称
char user_ipadrs[SHORT_STRING];//用户IP地址
char user_port[SHORT_STRING];//用户端口号
char user_serverport[SHORT_STRING];//用户供其他用户连接端口号,IP只有一个,所以无需多记录
int friend_id[MAXINFOSTRLENGTH];//用户好友索引
int yn_online;//用户是否在线
};
typedef struct sockaddr_in SocketAddress;
struct conMySocket
{
///客户端接入套接字描述
int con;
///客户端接入套接字
struct sockaddr_in clientSocket;
};
typedef struct localPortTagIPTagPort
{
//希望绑定的本地端口
int localPort;
//服务器IP
const char *tagserverIP;
//服务器端口
int tagserverPort;
}SelfBindPortAndTagInfo;
//绑定本地端口界面
int bindPortInterface();
//单纯显示登陆界面样式,不作功能判断
int loginInterface();
//输入帐号密码界面
void inputAccountPasswordInterface(char *account, char *password);
//将帐号密码发送至服务器核对,返回核对结果
int sendAccountPassword(int tagSocket, char *account, char *password);
//显示当前在线用户信息
int onLineUserInfo(int tagSocket);
//选择聊天或传送文件界面
int tagFunction();
//根据用户选择执行各界面显示流程
int controlChoose();
//客户端向另一客户端发送文件
int sendFile(int tagSocket);
//聊天实现
void chatWithTagUser(int tagSocket);
//客户端同另一客户端相连
int connectOtherUser(int tagSocket, int tagUserId);
void ttest(void *xx);
//客户端负责连接服务器和绑定本地端口的线程入口函数
void clientSelfServer(void *pPresentInfo);
//判断当前客户端是否已经同服务器连接
int sendOnlineInfo(int sendServerSocket, SocketAddress* mySocketAddress);
//单独处理聊天或传送文件的线程入口函数
void singleThrd(void *recvClientSockct);
//接收文件
int recvFile(int requestSocket);
#endif
好啦,关于socket的初步学习就到这里了,希望以后能再多多深入.