socket网络编程
面向套接字通信过程属于最基础的网络通信,本程序的特殊是使用通过配置文件的方式来配置服务器客户端的ip地址和端口演示程序如下所示。本程序使用的配置文件形式为.conf格式的,当然也可以采用.txt格式的配置文件。
使用方法:分别将两个代码gcc编译完成后,开两个终端,分别启动服务器和客户端则可实现通信。
服务器端先启动进行socket,bind,listen,accept等工作,客户端请求连接socket,connect。建立连接后进行服务请求和应答,执行相关发送和接受的操作,最后关闭文件描述符,完成通信。
配置文件完整代码
cls.conf
[cls_server]
#配置文件等号左右可以有空格也可以没有
ip=127.0.0.1
port=5566
服务器端完整代码
tcpserv.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <wait.h>
#include <errno.h>
#include <ctype.h>
#include <assert.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define KEYVALLEN 256
/* 删除左边的空格 */
char * l_trim(char * szOutput, const char *szInput);
/* 删除右边的空格 */
char *r_trim(char *szOutput, const char *szInput);
/* 删除两边的空格 */
char * a_trim(char * szOutput, const char * szInput);
int GetProfileString(char *profile, char *AppName, char *KeyName, char *KeyVal );
/* 删除左边的空格 */
char * l_trim(char * szOutput, const char *szInput)
{
assert(szInput != NULL);
assert(szOutput != NULL);
assert(szOutput != szInput);
for (NULL; *szInput != '\0' && isspace(*szInput); ++szInput){
;
}
return strcpy(szOutput, szInput);
}
/* 删除右边的空格 */
char *r_trim(char *szOutput, const char *szInput)
{
char *p = NULL;
assert(szInput != NULL);
assert(szOutput != NULL);
assert(szOutput != szInput);
strcpy(szOutput, szInput);
for(p = szOutput + strlen(szOutput) - 1; p >= szOutput && isspace(*p); --p){
;
}
*(++p) = '\0';
return szOutput;
}
/* 删除两边的空格 */
char * a_trim(char * szOutput, const char * szInput)
{
char *p = NULL;
assert(szInput != NULL);
assert(szOutput != NULL);
l_trim(szOutput, szInput);
for (p = szOutput + strlen(szOutput) - 1;p >= szOutput && isspace(*p); --p){
;
}
*(++p) = '\0';
return szOutput;
}
int GetProfileString(char *profile, char *AppName, char *KeyName, char *KeyVal )
{
char appname[32],keyname[32];
char *buf,*c;
char buf_i[KEYVALLEN], buf_o[KEYVALLEN];
FILE *fp;
int found=0; /* 1 AppName 2 KeyName */
if( (fp=fopen( profile,"r" ))==NULL ){
printf( "openfile [%s] error [%s]\n",profile,strerror(errno) );
return(-1);
}
fseek( fp, 0, SEEK_SET );
memset( appname, 0, sizeof(appname) );
sprintf( appname,"[%s]", AppName );
while( !feof(fp) && fgets( buf_i, KEYVALLEN, fp )!=NULL ){
l_trim(buf_o, buf_i);
if( strlen(buf_o) <= 0 )
continue;
buf = NULL;
buf = buf_o;
if( found == 0 ){
if( buf[0] != '[' ) {
continue;
} else if ( strncmp(buf,appname,strlen(appname))==0 ){
found = 1;
continue;
}
} else if( found == 1 ){
if( buf[0] == '#' ){
continue;
} else if ( buf[0] == '[' ) {
break;
} else {
if( (c = (char*)strchr(buf, '=')) == NULL )
continue;
memset( keyname, 0, sizeof(keyname) );
sscanf( buf, "%[^=|^ |^\t]", keyname );
if( strcmp(keyname, KeyName) == 0 ){
sscanf( ++c, "%[^\n]", KeyVal );
char *KeyVal_o = (char *)malloc(strlen(KeyVal) + 1);
if(KeyVal_o != NULL){
memset(KeyVal_o, 0, sizeof(KeyVal_o));
a_trim(KeyVal_o, KeyVal);
if(KeyVal_o && strlen(KeyVal_o) > 0)
strcpy(KeyVal, KeyVal_o);
free(KeyVal_o);
KeyVal_o = NULL;
}
found = 2;
break;
} else {
continue;
}
}
}
}
fclose( fp );
if( found == 2 )
return(0);
else
return(-1);
}
int main(void) {
char ip[16];
char port[16];
GetProfileString("./cls.conf", "cls_server", "ip", ip);
GetProfileString("./cls.conf", "cls_server", "port", port);
printf("服务器:创建网络套接字\n");
int sockfd = socket(PF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
perror("socket");
return -1;
}
printf("服务器:准备地址并绑定\n");
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(atoi(port));
addr.sin_addr.s_addr = INADDR_ANY;
if (bind(sockfd, (struct sockaddr*)&addr,
sizeof(addr)) == -1) {
perror("bind");
return -1;
}
printf("服务器:侦听套接字\n");
if (listen(sockfd, 1024) == -1) {
perror("listen");
return -1;
}
for (;;) {
printf("服务器:等待连接\n");
struct sockaddr_in addrcli = {};
socklen_t addrlen = sizeof(addrcli);
int connfd = accept(sockfd,
(struct sockaddr*)&addrcli,
&addrlen);
if (connfd == -1) {
perror("accept");
return -1;
}
printf("服务器:客户机%s:%u\n",
inet_ntoa(addrcli.sin_addr),
ntohs(addrcli.sin_port));
for (;;) {
char buf[1024];
ssize_t rb = recv(connfd, buf,
sizeof(buf), 0);
if (rb == -1) {
perror("recv");
return -1;
}
if (! strcmp(buf, "!\n"))
break;
printf("< %s", buf);
printf("%d:发送响应\n", getpid());
if (send(connfd, buf, rb, 0) == -1) {
perror("send");
return -1;
}
}
if (close(connfd) == -1) {
perror("close");
return -1;
}
}
return 0;
}
客户端完整代码
tcpcli.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define KEYVALLEN 256
/* 删除左边的空格 */
char * l_trim(char * szOutput, const char *szInput);
/* 删除右边的空格 */
char *r_trim(char *szOutput, const char *szInput);
/* 删除两边的空格 */
char * a_trim(char * szOutput, const char * szInput);
int GetProfileString(char *profile, char *AppName, char *KeyName, char *KeyVal );
/* 删除左边的空格 */
char * l_trim(char * szOutput, const char *szInput)
{
assert(szInput != NULL);
assert(szOutput != NULL);
assert(szOutput != szInput);
for (NULL; *szInput != '\0' && isspace(*szInput); ++szInput){
;
}
return strcpy(szOutput, szInput);
}
/* 删除右边的空格 */
char *r_trim(char *szOutput, const char *szInput)
{
char *p = NULL;
assert(szInput != NULL);
assert(szOutput != NULL);
assert(szOutput != szInput);
strcpy(szOutput, szInput);
for(p = szOutput + strlen(szOutput) - 1; p >= szOutput && isspace(*p); --p){
;
}
*(++p) = '\0';
return szOutput;
}
/* 删除两边的空格 */
char * a_trim(char * szOutput, const char * szInput)
{
char *p = NULL;
assert(szInput != NULL);
assert(szOutput != NULL);
l_trim(szOutput, szInput);
for (p = szOutput + strlen(szOutput) - 1;p >= szOutput && isspace(*p); --p){
;
}
*(++p) = '\0';
return szOutput;
}
int GetProfileString(char *profile, char *AppName, char *KeyName, char *KeyVal )
{
char appname[32],keyname[32];
char *buf,*c;
char buf_i[KEYVALLEN], buf_o[KEYVALLEN];
FILE *fp;
int found=0; /* 1 AppName 2 KeyName */
if( (fp=fopen( profile,"r" ))==NULL ){
printf( "openfile [%s] error [%s]\n",profile,strerror(errno) );
return(-1);
}
fseek( fp, 0, SEEK_SET );
memset( appname, 0, sizeof(appname) );
sprintf( appname,"[%s]", AppName );
while( !feof(fp) && fgets( buf_i, KEYVALLEN, fp )!=NULL ){
l_trim(buf_o, buf_i);
if( strlen(buf_o) <= 0 )
continue;
buf = NULL;
buf = buf_o;
if( found == 0 ){
if( buf[0] != '[' ) {
continue;
} else if ( strncmp(buf,appname,strlen(appname))==0 ){
found = 1;
continue;
}
} else if( found == 1 ){
if( buf[0] == '#' ){
continue;
} else if ( buf[0] == '[' ) {
break;
} else {
if( (c = (char*)strchr(buf, '=')) == NULL )
continue;
memset( keyname, 0, sizeof(keyname) );
sscanf( buf, "%[^=|^ |^\t]", keyname );
if( strcmp(keyname, KeyName) == 0 ){
sscanf( ++c, "%[^\n]", KeyVal );
char *KeyVal_o = (char *)malloc(strlen(KeyVal) + 1);
if(KeyVal_o != NULL){
memset(KeyVal_o, 0, sizeof(KeyVal_o));
a_trim(KeyVal_o, KeyVal);
if(KeyVal_o && strlen(KeyVal_o) > 0)
strcpy(KeyVal, KeyVal_o);
free(KeyVal_o);
KeyVal_o = NULL;
}
found = 2;
break;
} else {
continue;
}
}
}
}
fclose( fp );
if( found == 2 )
return(0);
else
return(-1);
}
int main(void) {
char ip[16];
char port[16];
GetProfileString("./cls.conf", "cls_server", "ip", ip);
GetProfileString("./cls.conf", "cls_server", "port", port);
printf("客户机:创建网络套接字\n");
int sockfd = socket(PF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
perror("socket");
return -1;
}
printf("客户机:准备地址并连接\n");
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(atoi(port));
addr.sin_addr.s_addr = inet_addr(ip);
if (connect(sockfd, (struct sockaddr*)&addr,
sizeof(addr)) == -1) {
perror("connect");
return -1;
}
for (;;) {
printf("> ");
char buf[1024];
fgets(buf, sizeof(buf) / sizeof(buf[0]),
stdin);
if (! strcmp(buf, "!\n"))
break;
printf("客户机:发送请求\n");
if (send(sockfd, buf, strlen(buf) *
sizeof(buf[0]), 0) == -1) {
perror("send");
return -1;
}
printf("客户机:接收响应\n");
ssize_t rb = recv(sockfd, buf,
sizeof(buf) - sizeof(buf[0]), 0);
if (rb == -1) {
perror("recv");
return -1;
}
if (rb == 0) {
printf("客户机:服务器已关闭\n");
break;
}
buf[rb / sizeof(buf[0])] = '\0';
printf("< %s", buf);
}
printf("客户机:关闭套接字\n");
if (close(sockfd) == -1) {
perror("close");
return -1;
}
printf("客户机:完成\n");
return 0;
}
执行过程
gcc -o tcpserv tcpserv.c
gcc -o tvcpcli tcpcli.c
一个终端执行客户端,另一个终端执行服务器,则可实现。