在Java里面进行socket编程是很容易的事情,为了更好地搞清楚socket运行机制,有必要了解一下linux下socket是如何运行的。由于涉及到底层的东西比较多,即使你本来很了解如何运用这些API,但究其下面层次的原理,如果不深入到源码的话,也是比较难以理解的。我本人理解的也不是很好,只能抛砖引玉了。
大概的流程如图所示:
1.服务器建立一个socket监听本机的某个端口(图中socket1)
2.客户机建立一个socket去连接服务器监听端口(如图中socketA)
3.服务器accept一个新的socket文件描述,表示服务器的某个进程要和某个IP的客户的某个进程进行通信了。
两台机通信的充分必要条件是 : 协议,源IP地址,源端口(端口就是进程的标示), 目标IP地址,目标端口,总共5个要素。
下面的代码主要展示的是单线程的聊天小程序。
主要思想就是基于以上流程,但是添加了log日志功能。上源码:
/* provide the function to log. input: environment varibles, (1) LEVEL=DEBUG||WARNING||ERROE (2)LOGPATH(the log file saving path) output: different level log file */ #ifndef _LOG_H_ #define _LOG_H_ #include <stdlib.h> #include <string.h> #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <time.h> //define the debug level #define DEBUG 5 #define WARNNING 4 #define ERROR 3 #define WORKKING 1 //if return 0,means ok, !=0, means not ok. int mylog(char * optional_msg,char * msg, int level); #endif
#include "log.h"
int mylog(char * optional_msg,char * msg, int level)
{
char * pc_level=getenv("LEVEL");
char * pc_path =getenv("LOGPATH");
//configure debug level
if(pc_level==NULL)
{
pc_level="WORKKING";
}
//printf("current level is %s\n",pc_level);
//configure path
char path[256];
if(pc_path==NULL)
{
getcwd(path, sizeof(path));
//printf("current path is %s\n",path);
pc_path=path;
}
//printf("configured path is %s\n",pc_path);
int int_src=0;
char *pc_preLog;
if(strcmp(pc_level,"DEBUG")==0)
{
int_src=5;
pc_preLog="[DEBUG] ";
}
if(strcmp(pc_level,"WARNNING")==0)
{
int_src=4;
pc_preLog="[WARNNING] ";
}
if(strcmp(pc_level,"ERROR")==0)
{
int_src=3;
pc_preLog="[ERROR] ";
}
if(strcmp(pc_level,"WORKKING")==0)
{
int_src=1;
pc_preLog="[WORKKING] ";
}
//create a file to write log.
char target_path[400];
strcpy(target_path,pc_path);
strcat(target_path,"/log.txt");
//printf("target path is %s\n",target_path);
if(int_src>=level)
{
int fileid=open(target_path,O_WRONLY|O_APPEND|O_CREAT,0);
if(fileid<0)
{
printf("create log file failed!\n");
exit(0);
}
write(fileid,optional_msg,strlen(optional_msg));
write(fileid,pc_preLog,strlen(pc_preLog));
write(fileid,msg,strlen(msg));
//set time
time_t timep;
time (&timep);
write(fileid," ----",strlen(" ----"));
write(fileid,ctime(&timep),strlen(ctime(&timep)));
write(fileid," \n",strlen(" \n"));
close(fileid);
}
return 0;
}
#include "log.h"
#include <stdio.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <signal.h>
#define BUFFER_SIZE 256
int client_socket_id=0;
void closeSocketId()
{
mylog("[Server] ","close socket file id",DEBUG);
close(client_socket_id);
}
void * receiveMsg(void * args)
{
while(1)
{
char buffer[BUFFER_SIZE]={0};
mylog("[Server] ","before receive.....",DEBUG);
int recv_length=recv(client_socket_id,buffer,BUFFER_SIZE,0);
mylog("[Server] ","after receive.....",DEBUG);
if (recv_length <= 0)
{
mylog("[Server] ","error comes when recieve data from server!",DEBUG);
exit(0);
}
printf("from server:%s\n",buffer);
}
return NULL;
}
void closeSocket()
{
mylog("[Server] "," positively close connection socket",DEBUG);
close(client_socket_id);
exit(0);
}
int main(int argc, char ** argv)
{
//setup the sigint
signal(SIGINT,closeSocket);
struct sockaddr_in server_addr,client_addr;
int size_of_addr=sizeof(server_addr);
//printf("size of addr is %d\n",size_of_addr);
//init server_addr;
bzero(&server_addr,sizeof(server_addr));
server_addr.sin_family=AF_INET;
server_addr.sin_port=htons(9999);
server_addr.sin_addr.s_addr=inet_addr("127.0.0.1");
char * pc;
pc=inet_ntoa(server_addr.sin_addr);
//printf("server11 ip is %s\n",pc);
int socketid=0;
//create socket file
mylog("[Server] ","before create socket......",DEBUG);
if((socketid=socket(AF_INET,SOCK_STREAM,0))<0)
mylog("[Server] ","create socket error",DEBUG);
mylog("[Server] ","after create socket......",DEBUG);
//bind
if(bind(socketid,(struct sockaddr*)&server_addr,size_of_addr)<0)
mylog("[Server] ","bind server address error",DEBUG);
//listen
mylog("[Server] ","before listen......",DEBUG);
if(listen(socketid,5)<0)
mylog("[Server] ","listen error",DEBUG);
mylog("[Server] ","after listen......",DEBUG);
socklen_t client_length=sizeof(client_addr);
mylog("[Server] ","before accept......",DEBUG);
client_socket_id=accept(socketid,(struct sockaddr*)&client_addr,&client_length);
mylog("[Server] ","after accept......",DEBUG);
if(client_socket_id<0)
mylog("[Server] "," client socket file id is negetive, worry",DEBUG);
//set receive thead
pthread_t pthread_id;
pthread_id=pthread_create(&pthread_id,NULL, receiveMsg,NULL);\
char *pcwelcome="welcome\n";
int length_string=strlen(pcwelcome);
send(client_socket_id,pcwelcome,length_string,0);
while(1)
{
char msg[BUFFER_SIZE];
//scanf("%[^n]",msg);
fgets(msg,BUFFER_SIZE,stdin);
int length_send=send(client_socket_id,msg,BUFFER_SIZE,0);
//printf("send msg length is %d\n",length_send);
if(length_send<0)
printf("send worry\n");
}
//close(client_socket_id);
return 0;
}
#include <stdio.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <signal.h>
#include "log.h"
#define BUFFER_SIZE 256
int socketid=0;
int client_result=0;
void * receiveMsg(void * args)
{
while(1)
{
if(client_result<0)
{
mylog("[Client] ","no connection",DEBUG);
exit(0);
}
char buffer[BUFFER_SIZE]={0};
mylog("[Client] ","before receive.....",DEBUG);
int recv_length=recv(socketid,buffer,BUFFER_SIZE,0);
mylog("[Client] ","after receive.....",DEBUG);
if (recv_length <= 0)
{
mylog("[Client] ","error comes when recieve data from server!",DEBUG);
exit(0);
}
printf("from server:%s\n",buffer);
}
}
void closeSocket()
{
printf(" positively close connection socket\n");
close(socketid);
exit(0);
}
int main(int argc, char ** argv)
{
//setup the sigint
signal(SIGINT,closeSocket);
struct sockaddr_in server_addr,client_addr;
int size_of_addr=sizeof(server_addr);
//printf("size of addr is %d\n",size_of_addr);
//init server_addr;
bzero(&server_addr,sizeof(client_addr));
client_addr.sin_family=AF_INET;
//char* pc_port=argv[1];
//printf("argv[1] %s\n",pc_port);
//int int_port=atoi(pc_port);
//printf("int_port %d\n",int_port);
client_addr.sin_port=htons(9998);
client_addr.sin_addr.s_addr=inet_addr("127.0.0.1");
char * pc;
pc=inet_ntoa(client_addr.sin_addr);
//printf("server ip is %s\n",pc);
//create socket file
if((socketid=socket(AF_INET,SOCK_STREAM,0))<0)
mylog("[Client] ","create socket error",DEBUG);
//bind
if(bind(socketid,(struct sockaddr*)&client_addr,size_of_addr)<0)
{
mylog("[Client] ","bind server address error",DEBUG);
exit(0);
}
server_addr.sin_family=AF_INET;
server_addr.sin_port=htons(9999);
server_addr.sin_addr.s_addr=inet_addr("127.0.0.1");
socklen_t server_length=sizeof(server_addr);
client_result=connect(socketid,(struct sockaddr*)&server_addr,server_length);
if(client_result<0)
printf("connect failed\n");
//set receive thead
pthread_t pthread_id;
pthread_id=pthread_create(&pthread_id,NULL, receiveMsg,NULL);
while(1)
{
char msg[BUFFER_SIZE]={0};
fgets(msg,BUFFER_SIZE,stdin);
int messageLength=strlen(msg);
//printf("message Length is %d\n",messageLength);
int length_send=send(socketid,msg,messageLength,0);
//printf("send msg length is %d\n",length_send);
if(length_send<0)
mylog("[Client] ","send worry",DEBUG);
}
close(socketid);
return 0;
}
编译运行方法:
1. 首先在自己的.profile里面设置环境变量export LEVEL=DEBUG,重启linux.LOGPATH不设置也可以,程序会给一个默认的,LEVEL当然也会,只有LEVEL=DEBUG的时候,log才会比较详细,log的等级嘛,像log4j,呵呵。
2. 编译
生成server.exe
gcc -Wall -g -lpthread log.h log.c server.c -o server.exe
生成client.exe
gcc -Wall -g -lpthread log.h log.c client.c -o client.exe
3 .执行
开一个终端
./server.exe
开一个终端
./client.exe
这一版写的比较粗糙,许多结构性设计的东西都是不合理的,比如mylog这个方法等等。等以后把多线程版本出了再修
该一下这个版本的。