socket通信属于IO操作,因此客户端通常会将要发送的数据一次性发送至服务器,待服务器处理后然后返回结果信息给客户端。趁着离职期间比较闲,写了个客户端socket通信库,日后用得着的话就可以直接用。
目录中的文件有:compile.sh libnetcom.so netcom.c netcom.h
netcom.h文件内容有:
#ifndef _NETCOM_H_
#define _NETCOM_H_
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
typedef struct st_socket_t
{
int socket;
char *recv_buff;
unsigned int cur_recv_index;
char *send_buff;
unsigned int cur_send_index;
unsigned int max_buff_len;
}st_socket_t;
int create_socket(st_socket_t **pp_socket);
int nc_conn(st_socket_t *p_socket, char *ip, int port);
int nc_get_one_byte(st_socket_t *p_socket, char *val);
int nc_get_n_byte(st_socket_t *p_socket, void *val, unsigned int n);
int nc_put_one_byte(st_socket_t *p_socket, char *val);
int nc_put_n_byte(st_socket_t *p_socket, void *val, unsigned int n);
int nc_send(st_socket_t *p_socket);
int nc_recv(st_socket_t *p_socket);
#endif
netcom.c文件内容有:
#include "netcom.h"
#define MAX_BUFF_LEN 8192
int create_socket(st_socket_t **pp_socket)
{
st_socket_t *p_socket = NULL;
p_socket = (st_socket_t *)malloc(sizeof(st_socket_t));
memset(p_socket, 0, sizeof(st_socket_t));
p_socket->socket = 0;
p_socket->max_buff_len = MAX_BUFF_LEN;
p_socket->recv_buff = (char *)malloc(sizeof(char) * MAX_BUFF_LEN);
memset(p_socket->recv_buff, 0, sizeof(char) * MAX_BUFF_LEN);
p_socket->send_buff = (char *)malloc(sizeof(char) * MAX_BUFF_LEN);
memset(p_socket->send_buff, 0, sizeof(char) * MAX_BUFF_LEN);
*pp_socket = p_socket;
return 0;
}
int nc_conn(st_socket_t *p_socket, char *ip, int port)
{
int ret = 0;
struct sockaddr_in sockaddr;
if (p_socket == NULL){
perror("p_socket == NULL");
}
p_socket->socket = socket(AF_INET, SOCK_STREAM, 0);
memset(&sockaddr, 0, sizeof(struct sockaddr_in));
sockaddr.sin_family = AF_INET;
sockaddr.sin_addr.s_addr = inet_addr(ip);
sockaddr.sin_port = htons(port);
ret = connect(p_socket->socket, &sockaddr, sizeof(struct sockaddr_in));
return ret;
}
int nc_get_one_byte(st_socket_t *p_socket, char *val)
{
if (val == NULL){
return -1;
}
*val = p_socket->recv_buff[p_socket->cur_recv_index++];
return 0;
}
int nc_get_n_byte(st_socket_t *p_socket, void *val, unsigned int n)
{
int pos = p_socket->cur_recv_index;
if (val == NULL){
return -1;
}
memcpy(val, p_socket->recv_buff + pos, n);
p_socket->cur_recv_index += n;
return 0;
}
int nc_put_one_byte(st_socket_t *p_socket, char *val)
{
int ret = 0;
if (val == NULL){
return -1;
}
p_socket->send_buff[p_socket->cur_send_index++] = *val;
if (p_socket->cur_send_index == MAX_BUFF_LEN){
ret = send(p_socket->socket, p_socket->send_buff, MAX_BUFF_LEN, 0);
p_socket->cur_send_index = 0;
return ret;
}
return 0;
}
int nc_put_n_byte(st_socket_t *p_socket, void *val, unsigned int n)
{
int ret = 0;
int i = 0;
for (i = 0; i < n; i++){
ret = nc_put_one_byte(p_socket, &val[i]);
if (ret < 0){
return ret;
}
}
}
int nc_send(st_socket_t *p_socket)
{
return send(p_socket->socket, p_socket->send_buff, p_socket->cur_send_index, 0);
}
int nc_recv(st_socket_t *p_socket)
{
return recv(p_socket->socket, p_socket->recv_buff, p_socket->max_buff_len, 0);
}
编译连接之后生成libnetcom.so文件。
以上代码在健壮性方面仍有不足,并且有很多特殊情况都没有考虑,后续再补充。下面写一个测试用例,测试库文件的基本功能。
服务器端测试文件server.c:
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#define SERVER_PORT 6000
#define BUFF_LEN 1024
int main(int argc, char *argv[])
{
int sock = 0, acc_sock = 0;
struct sockaddr_in sockaddr, acc_sock_addr;
int ret = 0;
sock = socket(AF_INET, SOCK_STREAM, 0);
memset(&sockaddr, 0, sizeof(struct sockaddr_in));
sockaddr.sin_family = AF_INET;
sockaddr.sin_addr.s_addr = INADDR_ANY;
sockaddr.sin_port = htons(SERVER_PORT);
ret = bind(sock,&sockaddr, sizeof(struct sockaddr_in));
if (ret < 0){
fprintf(stderr, "bind error--%s\n", strerror(errno));
exit(-1);
}
ret = listen(sock, 10);
if (ret < 0){
fprintf(stderr, "listen error--%s\n", strerror(errno));
exit(-1);
}
while (1)
{
socklen_t acc_addr_len = 0;
char buff[BUFF_LEN] = {0}, send_buff[BUFF_LEN] = {0};
acc_sock = accept(sock, &acc_sock_addr, &acc_addr_len);
if (acc_sock < 0){
fprintf(stdout, "accept error--%d\n", errno);
exit(-1);
}
printf("%s:%d connect to server\n", inet_ntoa(acc_sock_addr.sin_addr), acc_sock_addr.sin_port);
ret = recv(acc_sock, buff, sizeof(buff), 0);
sprintf(send_buff, "echo %s, %d", buff, ret);
ret = send(acc_sock, send_buff, strlen(send_buff), 0);
printf("send %d byte:%s\n", ret, send_buff);
}
return 0;
}
客户端测试文件client.c
#include "netcom/netcom.h"
#define IP "192.168.1.91"
#define PORT 6000
int main()
{
int ret = 0;
st_socket_t *p_socket = NULL;
char buff[] = "hello";
char ch = 0;
char recv_buff[1024] = "";
create_socket(&p_socket);
ret = nc_conn(p_socket, IP, PORT);
if (ret < 0){
perror("nc_conn");
exit(-1);
}
ret = nc_put_one_byte(p_socket, buff);
strcpy(buff, "good");
ret = nc_put_n_byte(p_socket, buff, strlen(buff));
ret = nc_send(p_socket);
ret = nc_recv(p_socket);
printf("recv %d byte\n", ret);
ret = nc_get_one_byte(p_socket, &ch);
printf("ch = %c\n", ch);
ret = nc_get_n_byte(p_socket, recv_buff, 10);
printf("recv_buff = %s\n", recv_buff);
return 0;
}
先执行服务器端,然后执行客户端之后:
[root@localhost echo]# ./server
255.127.0.0:60710 connect to server
send 13 byte:echo hgood, 5
root@szty-ThinkCentre-XXXX:lming_08# ./client
recv 13 byte
ch = e
recv_buff = cho hgood,
可以看出测试的效果还是不错的。